//! JSON deserialization //! //! _This module is only available if gluon is compiled with the `serialization` feature._ let { Value } = import! std.json let prim = import! std.json.prim let { Result, ? } = import! std.result let std_map @ { Map, ? } = import! std.map let { id } = import! std.function let float = import! std.float let functor = import! std.functor let { (*>), (<*), wrap } = import! std.applicative let { Alternative, (<|>) } = import! std.alternative let { flat_map } = import! std.monad let { for } = import! std.traversable let { ? } = import! std.array type Error = String type Deserializer i a = i -> Result Error { value : a, input : i } /// Deserializer which extracts the data from the `Value` type type ValueDeserializer a = Deserializer Value a let error_msg = id let deserializer : Deserializer i a -> Deserializer i a = id let functor : Functor (Deserializer i) = { map = \f m -> deserializer (\input -> do a = deserializer m input Ok { value = f a.value, input = a.input }), } let applicative : Applicative (Deserializer i) = { functor, apply = \f m -> deserializer (\input -> do g = deserializer f input do a = deserializer m g.input Ok { value = g.value a.value, input = a.input }), wrap = \value -> deserializer (\input -> Ok { value, input }), } let alternative : Alternative (Deserializer i) = { applicative, empty = deserializer (\stream -> Err (error_msg "empty")), or = \l r -> deserializer (\stream -> match deserializer l stream with | Ok a -> Ok a | Err _ -> deserializer r stream), } let monad : Monad (Deserializer i) = { applicative, flat_map = \f m -> deserializer (\input -> do a = deserializer m input deserializer (f a.value) a.input), } /// Deserializes a `Bool` /// /// ``` /// let { ? } = import! std.effect /// let { Value, bool, deserialize_with } = import! std.json.de /// let { Result, ? } = import! std.result /// let { assert_eq, ? } = import! std.test /// /// seq assert_eq (deserialize_with bool "true") (Ok True) /// assert_eq (deserialize_with bool "123") (Err "Expected bool") /// ``` let bool : ValueDeserializer Bool = \input -> match input with | Bool i -> Ok { value = i, input } | _ -> Err (error_msg "Expected bool") /// Deserializes a `Float` /// /// Note that the deserializer will "integers" such as 123 as floats /// /// ``` /// let { ? } = import! std.effect /// let { Value, float, deserialize_with } = import! std.json.de /// let { Result, ? } = import! std.result /// let { assert_eq, ? } = import! std.test /// /// seq assert_eq (deserialize_with float "123.45") (Ok 123.45) /// seq assert_eq (deserialize_with float "123") (Ok 123.0) /// assert_eq (deserialize_with float "true") (Err "Expected float") /// ``` let float : ValueDeserializer Float = \input -> match input with | Int i -> Ok { value = float.from_int i, input } | Float f -> Ok { value = f, input } | _ -> Err (error_msg "Expected float") /// Deserializes an `Int` /// /// ``` /// let { ? } = import! std.effect /// let { Value, int, deserialize_with } = import! std.json.de /// let { Result, ? } = import! std.result /// let { assert_eq, ? } = import! std.test /// /// seq assert_eq (deserialize_with int "123") (Ok 123) /// assert_eq (deserialize_with int "true") (Err "Expected integer") /// ``` let int : ValueDeserializer Int = \input -> match input with | Int i -> Ok { value = i, input } | _ -> Err (error_msg "Expected integer") /// Deserializes a `String` /// /// ``` /// let { ? } = import! std.effect /// let { Value, string, deserialize_with } = import! std.json.de /// let { Result, ? } = import! std.result /// let { assert_eq, ? } = import! std.test /// /// seq assert_eq (deserialize_with string "\"abc\"") (Ok "abc") /// assert_eq (deserialize_with string "true") (Err "Expected string") /// ``` let string : ValueDeserializer String = \input -> match input with | String s -> Ok { value = s, input } | _ -> Err (error_msg "Expected string") /// Deserializes an `Array` of `a` /// /// ``` /// let { ? } = import! std.effect /// let { Value, array, int, deserialize_with } = import! std.json.de /// let { Result, ? } = import! std.result /// let { ? } = import! std.array /// let { assert_eq, ? } = import! std.test /// /// seq assert_eq (deserialize_with (array int) "[123, 456]") (Ok [123, 456]) /// assert_eq (deserialize_with (array int) "[123, \"\"]") (Err "Expected integer") /// ``` let array a : ValueDeserializer a -> ValueDeserializer (Array a) = \input -> match input with | Array xs -> do value = for xs (\v -> do state = a v Ok state.value) Ok { value, input } | _ -> Err (error_msg "Expected array") /// Deserializes an `Option` of `a`. /// /// `null` maps to `None` and all other values to `a` /// /// ``` /// let { ? } = import! std.effect /// let { Value, option, int, deserialize_with } = import! std.json.de /// let { Result, ? } = import! std.result /// let { ? } = import! std.array /// let { assert_eq, ? } = import! std.test /// /// seq assert_eq (deserialize_with (option int) "123") (Ok (Some 123)) /// seq assert_eq (deserialize_with (option int) "null") (Ok None) /// assert_eq (deserialize_with (option int) "\"\"") (Err "Expected integer") /// ``` let option a : ValueDeserializer a -> ValueDeserializer (Option a) = \input -> match input with | Null -> Ok { value = None, input } | _ -> (functor.map Some a) input /// Deserializes the field `name` of an object using `a` /// /// ``` /// let { ? } = import! std.effect /// let { Value, field, int, deserialize_with } = import! std.json.de /// let { Result, ? } = import! std.result /// let { ? } = import! std.array /// let { assert_eq, ? } = import! std.test /// /// seq assert_eq (deserialize_with (field "test" int) "{ \"test\": 123 }") (Ok 123) /// assert_eq (deserialize_with (field "test" int) "{ \"abc\": 123 }") (Err "Expected field `test`") /// ``` let field name a : String -> ValueDeserializer a -> ValueDeserializer a = \input -> match input with | Object o -> match std_map.find name o with | Some value -> do state = a value Ok { value = state.value, input } | None -> Err (error_msg ("Expected field `" ++ name ++ "`")) | _ -> Err (error_msg "Expected map") /// Deserializes the a `Map String a` /// /// ``` /// let { ? } = import! std.effect /// let { Value, map, int, deserialize_with } = import! std.json.de /// let { Result, ? } = import! std.result /// let { singleton, ? } = import! std.map /// let { (<>) } = import! std.semigroup /// let { assert_eq, ? } = import! std.test /// /// seq assert_eq /// (deserialize_with (map int) r#"{ "test": 123, "test2": 0 }"#) /// (Ok (singleton "test" 123 <> singleton "test2" 0)) /// assert_eq (deserialize_with (map int) r#"{ "abc": "" }"#) (Err "Expected integer") /// ``` let map a : ValueDeserializer a -> ValueDeserializer (Map String a) = \input -> match input with | Object xs -> let f = \key value -> do state = a value Ok state.value do value = std_map.traverse_with_key f xs Ok { value, input } | _ -> Err (error_msg "Expected map") /// Deserializes a `Value` let value : ValueDeserializer Value = \input -> Ok { value = input, input } #[implicit] type Deserialize a = { deserializer : ValueDeserializer a } let deserializer ?d : [Deserialize a] -> ValueDeserializer a = d.deserializer let deserialize_with de input : ValueDeserializer a -> String -> Result Error a = do value = prim.deserialize input do state = de value Ok state.value /// Runs the deserializer `de` on `input` /// Produces a value of type `a` if deserialization was successful let deserialize ?de input : [Deserialize a] -> String -> Result Error a = deserialize_with de.deserializer input let run ?de value : [Deserialize a] -> Value -> Result Error a = do state = de.deserializer value Ok state.value let bool_deserializer : Deserialize Bool = { deserializer = bool } let int_deserializer : Deserialize Int = { deserializer = int } let float_deserializer : Deserialize Float = { deserializer = float } let string_deserializer : Deserialize String = { deserializer = string } let value_deserializer : Deserialize Value = { deserializer = value } let option_deserializer : [Deserialize a] -> Deserialize (Option a) = { deserializer = option deserializer } let list @ { List } = import! std.list let list_deserializer : [Deserialize a] -> Deserialize (List a) = { deserializer = functor.map list.of (array deserializer) } let array_deserializer : [Deserialize a] -> Deserialize (Array a) = { deserializer = array deserializer } let { Map } = import! std.map let map_deserializer : [Deserialize a] -> Deserialize (Map String a) = { deserializer = map deserializer } { Value, Error, Deserializer, ValueDeserializer, Deserialize, functor, applicative, alternative, monad, bool, int, float, string, array, field, map, option, value, deserialize, deserialize_with, run, deserializer, bool_deserializer, int_deserializer, string_deserializer, float_deserializer, value_deserializer, option_deserializer, list_deserializer, array_deserializer, map_deserializer, }