diff --git a/README.md b/README.md index 095913b..daa962d 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,5 @@ **WARNING**: This project is in its alpha phase and not yet production-ready. Use it with care! -`js-ffi` is a library allowing you to interact with basic JavaScript constructs from MoonBit. +`js-ffi` is a library allowing you to interact with basic JavaScript constructs from MoonBit, +ensuring as much null-safety as possible. diff --git a/src/js/async.mbt b/src/js/async.mbt index 54d9672..d8ac430 100644 --- a/src/js/async.mbt +++ b/src/js/async.mbt @@ -26,7 +26,7 @@ extern "js" fn Promise::wait_ffi( ///| pub async fn Promise::wait(self : Promise) -> Value! { - suspend!!(fn(k, ke) { Promise::wait_ffi(self, k, fn(e) { ke(Error_(e)) }) }) + suspend!(fn(k, ke) { Promise::wait_ffi(self, k, fn(e) { ke(Error_(e)) }) }) } ///| @@ -39,7 +39,7 @@ pub async fn Promise::wait(self : Promise) -> Value! { /// /// If you don't care about the result of the operation, you can use `spawn_detach` instead. pub fn Promise::unsafe_new[T](op : async () -> T!) -> Promise { - Promise::new_ffi(fn() { Value::cast_from(op!!()) }) + Promise::new_ffi(fn() { Value::from(op!()) }) } ///| @@ -50,7 +50,7 @@ extern "js" fn Promise::new_ffi(op : async () -> Value!) -> Promise = pub fn spawn_detach[T, E : Error](op : async () -> T!E) -> Unit { async_run(fn() { try { - op!!() |> ignore + op!() |> ignore } catch { _ => () } @@ -65,21 +65,21 @@ pub extern "js" fn Promise::all(promises : Array[Promise]) -> Promise = "(ps) => ///| /// Wraps each given `async fn` in a `Promise` and waits for all of them to resolve. pub async fn async_all![T](ops : Array[async () -> T!]) -> Array[T] { - async_all_raw!!(ops.map(fn(op) { async fn!() { Value::cast_from(op!!()) } })).map( - Value::cast, + async_all_raw!(ops.map(fn(op) { async fn!() { Value::from(op!()) } })).map( + Value::unsafe_into, ) } ///| async fn async_all_raw!(ops : Array[async () -> Value!]) -> Array[Value] { - Promise::all(ops.map(Promise::unsafe_new)).wait!!().cast() + Promise::all(ops.map(Promise::unsafe_new)).wait!().unsafe_into() } ///| pub fn async_test(op : async () -> Unit!) -> Unit { async_run(async fn() { try { - op!!() + op!() } catch { e => { println("ERROR in `async_test`: \{e}") diff --git a/src/js/async_deprecated.mbt b/src/js/async_deprecated.mbt index f3b6d66..09f939b 100644 --- a/src/js/async_deprecated.mbt +++ b/src/js/async_deprecated.mbt @@ -12,13 +12,13 @@ extern "js" fn async_wrap_ffi( ///| #deprecated("use Promise::wait instead") pub async fn async_wrap(op : AsyncOp) -> Value! { - suspend!!(fn(k, ke) { async_wrap_ffi(op, k, fn(e) { ke(Error_(e)) }) }) + suspend!(fn(k, ke) { async_wrap_ffi(op, k, fn(e) { ke(Error_(e)) }) }) } ///| #deprecated("use Promise::new instead") pub fn async_unwrap[T](op : async () -> T!) -> Promise { - Promise::new_ffi(fn() { Value::cast_from(op!!()) }) + Promise::new_ffi(fn() { Value::from(op!()) }) } ///| diff --git a/src/js/async_test.mbt b/src/js/async_test.mbt index f5979ed..6bcda65 100644 --- a/src/js/async_test.mbt +++ b/src/js/async_test.mbt @@ -5,7 +5,7 @@ async fn op1() -> String? { ///| async fn op2() -> String? { - guard op1!!() is Some(prefix) + guard op1!() is Some(prefix) Some(prefix + ", World") } @@ -18,7 +18,7 @@ async fn op3() -> String? { test "Promise::wait" { @js.async_test(fn!() { // Promise::unsafe_new + Promise::wait is a noop. - let res = @js.Promise::unsafe_new(fn() { op1!!() }).wait!!() + let res = @js.Promise::unsafe_new(fn() { op1!() }).wait!() assert_eq!(res.cast(), Some("Hello")) }) } @@ -27,7 +27,7 @@ test "Promise::wait" { test "async_all" { @js.async_test(fn!() { assert_eq!( - @js.async_all!!([fn() { op2!!() }, fn() { op1!!() }, fn() { op3!!() }]), + @js.async_all!([fn() { op2!() }, fn() { op1!() }, fn() { op3!() }]), [Some("Hello, World"), Some("Hello"), None], ) }) diff --git a/src/js/cast.mbt b/src/js/cast.mbt index eebf440..925c897 100644 --- a/src/js/cast.mbt +++ b/src/js/cast.mbt @@ -46,7 +46,7 @@ pub impl Cast for String with into(value) { ///| pub impl Cast for String with from(value) { - Value::cast_from(value) + Value::from(value) } ///| @@ -56,7 +56,7 @@ pub impl Cast for Int with into(value) { ///| pub impl Cast for Int with from(value) { - Value::cast_from(value) + Value::from(value) } ///| @@ -66,7 +66,7 @@ pub impl Cast for Double with into(value) { ///| pub impl Cast for Double with from(value) { - Value::cast_from(value) + Value::from(value) } ///| @@ -76,7 +76,7 @@ pub impl Cast for Bool with into(value) { ///| pub impl Cast for Bool with from(value) { - Value::cast_from(value) + Value::from(value) } ///| @@ -86,7 +86,7 @@ pub impl[A : Cast] Cast for Array[A] with into(value) { .bind(fn(arr) { let is_type_a = fn(elem) { not((Cast::into(elem) : A?).is_empty()) } if arr.iter().all(is_type_a) { - Some(Value::cast_from(arr).cast()) + Some(Value::from(arr).unsafe_into()) } else { None } @@ -95,5 +95,5 @@ pub impl[A : Cast] Cast for Array[A] with into(value) { ///| pub impl[A : Cast] Cast for Array[A] with from(value) { - Value::cast_from(value) + Value::from(value) } diff --git a/src/js/error.mbt b/src/js/error.mbt index 8eede11..2b610c0 100644 --- a/src/js/error.mbt +++ b/src/js/error.mbt @@ -9,7 +9,7 @@ pub fn Error_::cause(self : Error_) -> Value? { let Error_(inner) = self let cause = Error_::cause_ffi(inner) guard not(cause.is_undefined()) else { None } - Some(cause.cast()) + Some(cause.unsafe_into()) } ///| @@ -33,7 +33,7 @@ extern "js" fn Error_::wrap_ffi( ///| pub fn Error_::wrap[T]( op : () -> Value, - map_ok~ : (Value) -> T = Value::cast + map_ok~ : (Value) -> T = Value::unsafe_into ) -> T!Error_ { let mut res : Result[Value, Error_] = Ok(Value::undefined()) Error_::wrap_ffi(op, fn(v) { res = Ok(v) }, fn(e) { res = Err(Error_(e)) }) diff --git a/src/js/js.mbti b/src/js/js.mbti index 5ab1fcd..c90410e 100644 --- a/src/js/js.mbti +++ b/src/js/js.mbti @@ -64,10 +64,13 @@ impl Show for Error_ type Nullable[_] impl Nullable { from_option[T](T?) -> Self[T] + #deprecated get_exn[T](Self[T]) -> T is_null[T](Self[T]) -> Bool null[T]() -> Self[T] to_option[T](Self[T]) -> T? + unsafe_get[T](Self[T]) -> T + unwrap[T](Self[T]) -> T } pub type Object Value @@ -88,10 +91,13 @@ impl Object { type Optional[_] impl Optional { from_option[T](T?) -> Self[T] + #deprecated get_exn[T](Self[T]) -> T is_undefined[T](Self[T]) -> Bool to_option[T](Self[T]) -> T? undefined[T]() -> Self[T] + unsafe_get[T](Self[T]) -> T + unwrap[T](Self[T]) -> T } pub extern type Promise @@ -215,14 +221,18 @@ impl Value { apply_with_index[Arg, Result](Self, Int, Array[Arg]) -> Result apply_with_string[Arg, Result](Self, String, Array[Arg]) -> Result apply_with_symbol[Arg, Result](Self, Symbol, Array[Arg]) -> Result + #deprecated cast[T](Self) -> T + #deprecated cast_from[T](T) -> Self extends(Self, Self) -> Self + from[T](T) -> Self from_json(Json) -> Self! from_json_string(String) -> Self! get_with_index[T](Self, Int) -> T get_with_string[T](Self, String) -> T get_with_symbol[T](Self, Symbol) -> T + into[T](Self) -> T is_bool(Self) -> Bool is_null(Self) -> Bool is_number(Self) -> Bool @@ -240,6 +250,7 @@ impl Value { to_json(Self) -> Json! to_json_string(Self) -> String! to_string(Self) -> String + unsafe_into[T](Self) -> T } impl Show for Value impl @moonbitlang/core/json.FromJson for Value diff --git a/src/js/null.mbt b/src/js/null.mbt index 59b44e7..d13b7c1 100644 --- a/src/js/null.mbt +++ b/src/js/null.mbt @@ -3,24 +3,41 @@ extern type Nullable[_] ///| pub fn Nullable::is_null[T](self : Nullable[T]) -> Bool { - Value::is_null(Value::cast_from(self)) + Value::is_null(Value::from(self)) } ///| +#deprecated("get_exn is not null-safety. Use `unwrap` or `unsafe_get` instead.") pub fn Nullable::get_exn[T](self : Nullable[T]) -> T = "%identity" -///| +///| Get the underlying value without checking for null. +/// +/// This is unsafe and should only be used when you are sure that the value is not null. +/// It's recommended to use `unwrap` instead. +pub fn Nullable::unsafe_get[T](self : Nullable[T]) -> T = "%identity" + +///| Get the underlying value with checking for null. +/// +/// If the value is null, it will abort the program. +pub fn Nullable::unwrap[T](self : Nullable[T]) -> T { + if self.is_null() { + abort("unwrap on null") + } + self.unsafe_get() +} + +///| Convert a Nullable value to an Option. pub fn Nullable::to_option[T](self : Nullable[T]) -> T? { - guard not(Value::cast_from(self).is_null()) else { None } - Some(self.get_exn()) + guard not(Value::from(self).is_null()) else { None } + Some(self.unsafe_get()) } ///| pub fn Nullable::null[T]() -> Nullable[T] { - Value::null().cast() + Value::null().unsafe_into() } ///| pub fn Nullable::from_option[T](value : T?) -> Nullable[T] { - value.map(Value::cast_from).or_else(Value::null).cast() + value.map(Value::from).or_else(Value::null).unsafe_into() } diff --git a/src/js/object.mbt b/src/js/object.mbt index 83062bc..5936801 100644 --- a/src/js/object.mbt +++ b/src/js/object.mbt @@ -48,10 +48,10 @@ pub fn Object::from_iter2[K, V](it : Iter2[K, V]) -> Object { ///| pub fn Object::op_get[K, V](self : Object, key : K) -> V { - self._.get_ffi(Value::cast_from(key)).cast() + self._.get_ffi(Value::from(key)).unsafe_into() } ///| pub fn Object::op_set[K, V](self : Object, key : K, value : V) -> Unit { - self._.set_ffi(Value::cast_from(key), Value::cast_from(value)) + self._.set_ffi(Value::from(key), Value::from(value)) } diff --git a/src/js/optional.mbt b/src/js/optional.mbt index 767085d..38ede0f 100644 --- a/src/js/optional.mbt +++ b/src/js/optional.mbt @@ -3,30 +3,44 @@ extern type Optional[_] ///| pub fn Optional::is_undefined[T](self : Optional[T]) -> Bool { - self |> Value::cast_from |> Value::is_undefined + self |> Value::from |> Value::is_undefined } -///| +///| +#deprecated("get_exn is not undefined-safety. Use `unwrap` or `to_option` instead.") pub fn Optional::get_exn[T](self : Optional[T]) -> T = "%identity" -///| +///| Get the underlying value without checking for undefined. +pub fn Optional::unsafe_get[T](self : Optional[T]) -> T = "%identity" + +///| Get the underlying value with checking for undefined. +/// +/// If the value is undefined, it will abort the program. +pub fn Optional::unwrap[T](self : Optional[T]) -> T { + if self.is_undefined() { + abort("unwrap on undefined") + } + self.unsafe_get() +} + +///| Convert an Optional value to an Option. pub fn Optional::to_option[T](self : Optional[T]) -> T? { - if Value::cast_from(self).is_undefined() { + if Value::from(self).is_undefined() { None } else { - Some(self.get_exn()) + Some(self.unsafe_get()) } } ///| pub fn Optional::undefined[T]() -> Optional[T] { - Value::undefined().cast() + Value::undefined().unsafe_into() } ///| pub fn Optional::from_option[T](value : T?) -> Optional[T] { match value { - Some(v) => Value::cast_from(v).cast() + Some(v) => Value::from(v).unsafe_into() None => Optional::undefined() } } diff --git a/src/js/require.mbt b/src/js/require.mbt index 8a4479e..8ad369d 100644 --- a/src/js/require.mbt +++ b/src/js/require.mbt @@ -4,6 +4,6 @@ extern "js" fn require_ffi(path : String) -> Value = "(path) => require(path)" ///| pub fn require(path : String, keys~ : Array[String] = []) -> Value { keys.fold(init=require_ffi(path), fn { - acc, key => get_ffi(acc, Value::cast_from(key)) + acc, key => get_ffi(acc, Value::from(key)) }) } diff --git a/src/js/symbol.mbt b/src/js/symbol.mbt index f4fd347..262eaf8 100644 --- a/src/js/symbol.mbt +++ b/src/js/symbol.mbt @@ -3,12 +3,12 @@ extern type Symbol ///| pub fn Symbol::make() -> Symbol { - Symbol::make_ffi(Value::undefined()).cast() + Symbol::make_ffi(Value::undefined()).unsafe_into() } ///| pub fn Symbol::make_with_string_js(value : String) -> Symbol { - Symbol::make_ffi(Value::cast_from(value)).cast() + Symbol::make_ffi(Value::from(value)).unsafe_into() } ///| @@ -18,7 +18,7 @@ pub fn Symbol::make_with_string(value : String) -> Symbol { ///| pub fn Symbol::make_with_number(num : Double) -> Symbol { - Symbol::make_ffi(Value::cast_from(num)).cast() + Symbol::make_ffi(Value::from(num)).unsafe_into() } ///| @@ -30,11 +30,11 @@ extern "js" fn Symbol::iterator_ffi() -> Value = #| () => Symbol.iterator ///| -pub let iterator : Symbol = Symbol::iterator_ffi().cast() +pub let iterator : Symbol = Symbol::iterator_ffi().unsafe_into() ///| extern "js" fn Symbol::async_iterator_ffi() -> Value = #| () => Symbol.asyncIterator ///| -pub let async_iterator : Symbol = Symbol::async_iterator_ffi().cast() +pub let async_iterator : Symbol = Symbol::async_iterator_ffi().unsafe_into() diff --git a/src/js/union.mbt b/src/js/union.mbt index a0cd86a..0f29281 100644 --- a/src/js/union.mbt +++ b/src/js/union.mbt @@ -3,22 +3,22 @@ extern type Union2[_, _] ///| pub fn Union2::to0[A : Cast, B](self : Union2[A, B]) -> A? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union2::to1[A, B : Cast](self : Union2[A, B]) -> B? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union2::from0[A : Cast, B](value : A) -> Union2[A, B] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union2::from1[A, B : Cast](value : B) -> Union2[A, B] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| Union type `A | B | C` for JavaScript values. @@ -26,32 +26,32 @@ extern type Union3[_, _, _] ///| pub fn Union3::to0[A : Cast, B, C](self : Union3[A, B, C]) -> A? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union3::to1[A, B : Cast, C](self : Union3[A, B, C]) -> B? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union3::to2[A, B, C : Cast](self : Union3[A, B, C]) -> C? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union3::from0[A : Cast, B, C](value : A) -> Union3[A, B, C] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union3::from1[A, B : Cast, C](value : B) -> Union3[A, B, C] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union3::from2[A, B, C : Cast](value : C) -> Union3[A, B, C] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| Union type `A | B | C | D` for JavaScript values. @@ -59,42 +59,42 @@ extern type Union4[_, _, _, _] ///| pub fn Union4::to0[A : Cast, B, C, D](self : Union4[A, B, C, D]) -> A? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union4::to1[A, B : Cast, C, D](self : Union4[A, B, C, D]) -> B? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union4::to2[A, B, C : Cast, D](self : Union4[A, B, C, D]) -> C? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union4::to3[A, B, C, D : Cast](self : Union4[A, B, C, D]) -> D? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union4::from0[A : Cast, B, C, D](value : A) -> Union4[A, B, C, D] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union4::from1[A, B : Cast, C, D](value : B) -> Union4[A, B, C, D] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union4::from2[A, B, C : Cast, D](value : C) -> Union4[A, B, C, D] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union4::from3[A, B, C, D : Cast](value : D) -> Union4[A, B, C, D] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| Union type `A | B | C | D | E` for JavaScript values. @@ -102,52 +102,52 @@ extern type Union5[_, _, _, _, _] ///| pub fn Union5::to0[A : Cast, B, C, D, E](self : Union5[A, B, C, D, E]) -> A? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union5::to1[A, B : Cast, C, D, E](self : Union5[A, B, C, D, E]) -> B? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union5::to2[A, B, C : Cast, D, E](self : Union5[A, B, C, D, E]) -> C? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union5::to3[A, B, C, D : Cast, E](self : Union5[A, B, C, D, E]) -> D? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union5::to4[A, B, C, D, E : Cast](self : Union5[A, B, C, D, E]) -> E? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union5::from0[A : Cast, B, C, D, E](value : A) -> Union5[A, B, C, D, E] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union5::from1[A, B : Cast, C, D, E](value : B) -> Union5[A, B, C, D, E] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union5::from2[A, B, C : Cast, D, E](value : C) -> Union5[A, B, C, D, E] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union5::from3[A, B, C, D : Cast, E](value : D) -> Union5[A, B, C, D, E] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union5::from4[A, B, C, D, E : Cast](value : E) -> Union5[A, B, C, D, E] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| Union type `A | B | C | D | E | F` for JavaScript values. @@ -157,84 +157,84 @@ extern type Union6[_, _, _, _, _, _] pub fn Union6::to0[A : Cast, B, C, D, E, F]( self : Union6[A, B, C, D, E, F] ) -> A? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union6::to1[A, B : Cast, C, D, E, F]( self : Union6[A, B, C, D, E, F] ) -> B? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union6::to2[A, B, C : Cast, D, E, F]( self : Union6[A, B, C, D, E, F] ) -> C? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union6::to3[A, B, C, D : Cast, E, F]( self : Union6[A, B, C, D, E, F] ) -> D? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union6::to4[A, B, C, D, E : Cast, F]( self : Union6[A, B, C, D, E, F] ) -> E? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union6::to5[A, B, C, D, E, F : Cast]( self : Union6[A, B, C, D, E, F] ) -> F? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union6::from0[A : Cast, B, C, D, E, F]( value : A ) -> Union6[A, B, C, D, E, F] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union6::from1[A, B : Cast, C, D, E, F]( value : B ) -> Union6[A, B, C, D, E, F] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union6::from2[A, B, C : Cast, D, E, F]( value : C ) -> Union6[A, B, C, D, E, F] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union6::from3[A, B, C, D : Cast, E, F]( value : D ) -> Union6[A, B, C, D, E, F] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union6::from4[A, B, C, D, E : Cast, F]( value : E ) -> Union6[A, B, C, D, E, F] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union6::from5[A, B, C, D, E, F : Cast]( value : F ) -> Union6[A, B, C, D, E, F] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| Union type `A | B | C | D | E | F | G` for JavaScript values. @@ -244,98 +244,98 @@ extern type Union7[_, _, _, _, _, _, _] pub fn Union7::to0[A : Cast, B, C, D, E, F, G]( self : Union7[A, B, C, D, E, F, G] ) -> A? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union7::to1[A, B : Cast, C, D, E, F, G]( self : Union7[A, B, C, D, E, F, G] ) -> B? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union7::to2[A, B, C : Cast, D, E, F, G]( self : Union7[A, B, C, D, E, F, G] ) -> C? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union7::to3[A, B, C, D : Cast, E, F, G]( self : Union7[A, B, C, D, E, F, G] ) -> D? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union7::to4[A, B, C, D, E : Cast, F, G]( self : Union7[A, B, C, D, E, F, G] ) -> E? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union7::to5[A, B, C, D, E, F : Cast, G]( self : Union7[A, B, C, D, E, F, G] ) -> F? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union7::to6[A, B, C, D, E, F, G : Cast]( self : Union7[A, B, C, D, E, F, G] ) -> G? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union7::from0[A : Cast, B, C, D, E, F, G]( value : A ) -> Union7[A, B, C, D, E, F, G] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union7::from1[A, B : Cast, C, D, E, F, G]( value : B ) -> Union7[A, B, C, D, E, F, G] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union7::from2[A, B, C : Cast, D, E, F, G]( value : C ) -> Union7[A, B, C, D, E, F, G] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union7::from3[A, B, C, D : Cast, E, F, G]( value : D ) -> Union7[A, B, C, D, E, F, G] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union7::from4[A, B, C, D, E : Cast, F, G]( value : E ) -> Union7[A, B, C, D, E, F, G] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union7::from5[A, B, C, D, E, F : Cast, G]( value : F ) -> Union7[A, B, C, D, E, F, G] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union7::from6[A, B, C, D, E, F, G : Cast]( value : G ) -> Union7[A, B, C, D, E, F, G] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| Union type `A | B | C | D | E | F | G | H` for JavaScript values. @@ -345,110 +345,110 @@ extern type Union8[_, _, _, _, _, _, _, _] pub fn Union8::to0[A : Cast, B, C, D, E, F, G, H]( self : Union8[A, B, C, D, E, F, G, H] ) -> A? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union8::to1[A, B : Cast, C, D, E, F, G, H]( self : Union8[A, B, C, D, E, F, G, H] ) -> B? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union8::to2[A, B, C : Cast, D, E, F, G, H]( self : Union8[A, B, C, D, E, F, G, H] ) -> C? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union8::to3[A, B, C, D : Cast, E, F, G, H]( self : Union8[A, B, C, D, E, F, G, H] ) -> D? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union8::to4[A, B, C, D, E : Cast, F, G, H]( self : Union8[A, B, C, D, E, F, G, H] ) -> E? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union8::to5[A, B, C, D, E, F : Cast, G, H]( self : Union8[A, B, C, D, E, F, G, H] ) -> F? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union8::to6[A, B, C, D, E, F, G : Cast, H]( self : Union8[A, B, C, D, E, F, G, H] ) -> G? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union8::to7[A, B, C, D, E, F, G, H : Cast]( self : Union8[A, B, C, D, E, F, G, H] ) -> H? { - Cast::into(Value::cast_from(self)) + Cast::into(Value::from(self)) } ///| pub fn Union8::from0[A : Cast, B, C, D, E, F, G, H]( value : A ) -> Union8[A, B, C, D, E, F, G, H] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union8::from1[A, B : Cast, C, D, E, F, G, H]( value : B ) -> Union8[A, B, C, D, E, F, G, H] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union8::from2[A, B, C : Cast, D, E, F, G, H]( value : C ) -> Union8[A, B, C, D, E, F, G, H] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union8::from3[A, B, C, D : Cast, E, F, G, H]( value : D ) -> Union8[A, B, C, D, E, F, G, H] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union8::from4[A, B, C, D, E : Cast, F, G, H]( value : E ) -> Union8[A, B, C, D, E, F, G, H] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union8::from5[A, B, C, D, E, F : Cast, G, H]( value : F ) -> Union8[A, B, C, D, E, F, G, H] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union8::from6[A, B, C, D, E, F, G : Cast, H]( value : G ) -> Union8[A, B, C, D, E, F, G, H] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } ///| pub fn Union8::from7[A, B, C, D, E, F, G, H : Cast]( value : H ) -> Union8[A, B, C, D, E, F, G, H] { - Cast::from(value).cast() + Cast::from(value).unsafe_into() } diff --git a/src/js/value.mbt b/src/js/value.mbt index 244eeaa..1d69973 100644 --- a/src/js/value.mbt +++ b/src/js/value.mbt @@ -2,11 +2,32 @@ pub extern type Value ///| +#deprecated("Use `Value::from` instead.") pub fn Value::cast_from[T](value : T) -> Value = "%identity" -///| +///| +#deprecated("Use `Value::into` or `Value::unsafe_into` instead.") pub fn Value::cast[T](self : Value) -> T = "%identity" +///| Create a `Value` from any type, checking for null or undefined. +pub fn Value::from[T](self : T) -> Value = "%identity" + +///| Cast a `Value` to any type, without checking for null or undefined. +pub fn Value::unsafe_into[T](self : Value) -> T = "%identity" + +///| Convert a `Value` to any type, checking for null or undefined. +/// +/// If the value is null or undefined, it will abort the program. +pub fn Value::into[T](self : Value) -> T { + if self.is_null() { + abort("Value::cast on null") + } + if self.is_undefined() { + abort("Value::cast on undefined") + } + self.unsafe_into() +} + ///| pub extern "js" fn Value::to_string(self : Value) -> String = "(self) => self.toString()" @@ -20,38 +41,38 @@ pub let globalThis : Value = get_globalThis() ///| pub fn get_with_string[T](self : Value, key : String) -> T { - self.get_ffi(Value::cast_from(key)).cast() + self.get_ffi(Value::from(key)).unsafe_into() } ///| pub fn get_with_symbol[T](self : Value, key : Symbol) -> T { - self.get_ffi(Value::cast_from(key)).cast() + self.get_ffi(Value::from(key)).unsafe_into() } ///| pub fn get_with_index[T](self : Value, index : Int) -> T { - self.get_ffi(Value::cast_from(index)).cast() + self.get_ffi(Value::from(index)).unsafe_into() } ///| pub fn set_with_string[T](self : Value, key : String, value : T) -> Unit { - self.set_ffi(Value::cast_from(key), Value::cast_from(value)) + self.set_ffi(Value::from(key), Value::from(value)) } ///| pub fn set_with_symbol[T](self : Value, key : Symbol, value : T) -> Unit { - self.set_ffi(Value::cast_from(key), Value::cast_from(value)) + self.set_ffi(Value::from(key), Value::from(value)) } ///| pub fn set_with_index[T](self : Value, index : Int, value : T) -> Unit { - self.set_ffi(Value::cast_from(index), Value::cast_from(value)) + self.set_ffi(Value::from(index), Value::from(value)) } ///| /// `self(...args)` pub fn Value::apply[Arg, Result](self : Value, args : Array[Arg]) -> Result { - self.apply_self_ffi(Value::cast_from(args)).cast() + self.apply_self_ffi(Value::from(args)).unsafe_into() } ///| @@ -61,7 +82,7 @@ pub fn Value::apply_with_string[Arg, Result]( key : String, args : Array[Arg] ) -> Result { - self.apply_ffi(Value::cast_from(key), Value::cast_from(args)).cast() + self.apply_ffi(Value::from(key), Value::from(args)).unsafe_into() } ///| @@ -71,7 +92,7 @@ pub fn Value::apply_with_symbol[Arg, Result]( key : Symbol, args : Array[Arg] ) -> Result { - self.apply_ffi(Value::cast_from(key), Value::cast_from(args)).cast() + self.apply_ffi(Value::from(key), Value::from(args)).unsafe_into() } ///| @@ -81,13 +102,13 @@ pub fn Value::apply_with_index[Arg, Result]( index : Int, args : Array[Arg] ) -> Result { - self.apply_ffi(Value::cast_from(index), Value::cast_from(args)).cast() + self.apply_ffi(Value::from(index), Value::from(args)).unsafe_into() } ///| /// `new self(...args)` pub fn Value::new[Arg, Result](self : Value, args : Array[Arg]) -> Result { - self.new_self_ffi(Value::cast_from(args)).cast() + self.new_self_ffi(Value::from(args)).unsafe_into() } ///| @@ -97,7 +118,7 @@ pub fn Value::new_with_string[Arg, Result]( key : String, args : Array[Arg] ) -> Result { - self.new_ffi(Value::cast_from(key), Value::cast_from(args)).cast() + self.new_ffi(Value::from(key), Value::from(args)).unsafe_into() } ///| @@ -107,7 +128,7 @@ pub fn Value::new_with_symbol[Arg, Result]( key : Symbol, args : Array[Arg] ) -> Result { - self.new_ffi(Value::cast_from(key), Value::cast_from(args)).cast() + self.new_ffi(Value::from(key), Value::from(args)).unsafe_into() } ///| @@ -117,7 +138,7 @@ pub fn Value::new_with_index[Arg, Result]( index : Int, args : Array[Arg] ) -> Result { - self.new_ffi(Value::cast_from(index), Value::cast_from(args)).cast() + self.new_ffi(Value::from(index), Value::from(args)).unsafe_into() } ///| @@ -128,17 +149,17 @@ pub fn Value::from_json!(json : Json) -> Value { ///| pub impl @json.FromJson for Value with from_json(json : Json, path) { match json { - String(s) => Value::cast_from(s) - Number(n) => Value::cast_from(n) - False => Value::cast_from(false) - True => Value::cast_from(true) + String(s) => Value::from(s) + Number(n) => Value::from(n) + False => Value::from(false) + True => Value::from(true) Null => Value::null() Array(xs) => { let acc = Array::new(capacity=xs.length()) for x in xs { acc.push((@json.from_json!(x, path~) : Value)) } - Value::cast_from(acc) + Value::from(acc) } Object(kvs) => { let acc = Object::new()