Skip to content

Commit

Permalink
Add Binding.overBoth' and remove constaints on overBoth, `overBin…
Browse files Browse the repository at this point in the history
…ding` and `overValue`

Enables updating widgets without `unsafeCoerce`
  • Loading branch information
postsolar committed Feb 24, 2024
1 parent fc8bc14 commit a2c786e
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 10 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Unreleased

- Add `Binding.overBoth'` and remove constraints from `overValue`, `overBinding` and `overBoth`

## v0.2.0

- Refactor GObject type classes (#14)
Expand Down
6 changes: 6 additions & 0 deletions src/AGS/Binding.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Binding } from 'resource:///com/github/Aylur/ags/service.js'

export const unsafeBindProp =
prop => object =>
object.bind(prop)
Expand Down Expand Up @@ -26,3 +28,7 @@ export const bindBinding =
return watcher.bind()
}

export const isBinding =
val =>
val instanceof Binding

35 changes: 25 additions & 10 deletions src/AGS/Binding.purs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ module AGS.Binding
, overValue
, overBinding
, overBoth
, overBoth'
) where

import Prelude

import Control.Apply (lift2)
import Data.Either (either)
import Data.Symbol (class IsSymbol, reflectSymbol)
import Prim.Row as R
import Type.Proxy (Proxy(..))
import Untagged.TypeCheck (class HasRuntimeType)
import Untagged.Union (OneOf, asOneOf, toEither1)
import Unsafe.Coerce (unsafeCoerce)
import Untagged.Union (OneOf, asOneOf)

foreign import data Binding Type Type

Expand Down Expand Up @@ -74,12 +74,16 @@ foreign import unsafeBindProp ∷ ∀ o t. String → o → Binding t

type ValueOrBinding a = OneOf a (Binding a)

-- Technically there's no guarantee of distinguishing between
-- a `Bidning a` as a value and a `Binding (Binding a)` as a binding,
-- but in practice it's not relevant for widgets because it's a type error
-- to put a nested binding into any of their props anyways.

-- | Transform a *value* inside a `ValueOrBinding`.
-- | If `ValueOrBinding` is a binding, it stays unmodified.
overValue
a
. HasRuntimeType a
(a a)
. (a a)
ValueOrBinding a
ValueOrBinding a
overValue = flip overBoth identity
Expand All @@ -88,19 +92,30 @@ overValue = flip overBoth identity
-- | If `ValueOrBinding` is a plain value, it stays unmodified.
overBinding
a
. HasRuntimeType a
(Binding a Binding a)
. (Binding a Binding a)
ValueOrBinding a
ValueOrBinding a
overBinding = overBoth identity

-- | Transform both a plain value and a binding in `ValueOrBinding`.
overBoth
a b
. HasRuntimeType a
(a b)
. (a b)
(Binding a Binding b)
ValueOrBinding a
ValueOrBinding b
overBoth f g sob = either (asOneOf <<< f) (asOneOf <<< g) $ toEither1 sob
overBoth f g vob
| isBinding vob = asOneOf $ g (unsafeCoerce vob Binding a)
| otherwise = asOneOf $ f (unsafeCoerce vob a)

-- | Transform both a plain value and a binding in `ValueOrBinding`,
-- | with the same function for each case.
overBoth'
a b
. (a b)
ValueOrBinding a
ValueOrBinding b
overBoth' f = overBoth f (map f)

foreign import isBinding a. a Boolean

0 comments on commit a2c786e

Please sign in to comment.