aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLouis Pilfold <louis@lpil.uk>2019-03-17 15:35:19 +0000
committerLouis Pilfold <louis@lpil.uk>2019-03-17 15:35:19 +0000
commitfbd570295cd40802127913d2b308916eefb14066 (patch)
tree5a018e14b69d7748459091c97afa9e1cd7972d1d /src
parent00ff9767dc61e698aac791b43704cfce1ab33600 (diff)
downloadgleam_stdlib-fbd570295cd40802127913d2b308916eefb14066.tar.gz
gleam_stdlib-fbd570295cd40802127913d2b308916eefb14066.zip
Any decoders
Diffstat (limited to 'src')
-rw-r--r--src/any.gleam287
-rw-r--r--src/gleam__stdlib.erl39
-rw-r--r--src/result.gleam21
3 files changed, 333 insertions, 14 deletions
diff --git a/src/any.gleam b/src/any.gleam
index 884a436..41abed3 100644
--- a/src/any.gleam
+++ b/src/any.gleam
@@ -1,3 +1,7 @@
+import list
+import result
+import expect
+
// `Any` data is data that we don"t know the type of yet.
// We likely get data like this from interop with Erlang, or from
// IO with the outside world.
@@ -14,3 +18,286 @@ pub external fn from(a) -> Any = "gleam__stdlib" "identity";
// native Erlang APIs. It is to be used as a last measure only.
//
pub external fn unsafeCoerce(a) -> b = "gleam__stdlib" "identity";
+
+pub external fn string(Any) -> Result(String, String)
+ = "gleam__stdlib" "decode_string"
+
+test string {
+ ""
+ |> from
+ |> string
+ |> expect:equal(_, Ok(""))
+
+ "Hello"
+ |> from
+ |> string
+ |> expect:equal(_, Ok("Hello"))
+
+ 1
+ |> from
+ |> string
+ |> expect:equal(_, Error("Expected a String, got `1`"))
+
+ []
+ |> from
+ |> string
+ |> expect:equal(_, Error("Expected a String, got `[]`"))
+}
+
+pub external fn int(Any) -> Result(Int, String)
+ = "gleam__stdlib" "decode_int"
+
+test int {
+ 1
+ |> from
+ |> int
+ |> expect:equal(_, Ok(1))
+
+ 2
+ |> from
+ |> int
+ |> expect:equal(_, Ok(2))
+
+ 1.0
+ |> from
+ |> int
+ |> expect:equal(_, Error("Expected an Int, got `1.0`"))
+
+ []
+ |> from
+ |> int
+ |> expect:equal(_, Error("Expected an Int, got `[]`"))
+}
+
+pub external fn float(Any) -> Result(Float, String)
+ = "gleam__stdlib" "decode_float"
+
+test float {
+ 1.0
+ |> from
+ |> float
+ |> expect:equal(_, Ok(1.0))
+
+ 2.2
+ |> from
+ |> float
+ |> expect:equal(_, Ok(2.2))
+
+ 1
+ |> from
+ |> float
+ |> expect:equal(_, Error("Expected a Float, got `1`"))
+
+ []
+ |> from
+ |> float
+ |> expect:equal(_, Error("Expected a Float, got `[]`"))
+}
+
+// pub external fn atom(Any) -> Result(Atom, String)
+// = "gleam__stdlib" "decode_atom"
+
+//// test atom {
+//// // TODO
+//// // make an atom here
+//// // |> from
+//// // |> atom
+//// // |> expect:equal(_, Ok(""))
+
+//// // TODO
+//// // make an atom here
+//// // |> from
+//// // |> atom
+//// // |> expect:equal(_, Ok("ok"))
+
+//// let _ = 1
+//// |> from
+//// |> atom
+//// |> expect:is_error
+
+//// []
+//// |> from
+//// |> atom
+//// |> expect:is_error
+//// }
+
+pub external fn bool(Any) -> Result(Bool, String)
+ = "gleam__stdlib" "decode_bool"
+
+test bool {
+ True
+ |> from
+ |> bool
+ |> expect:equal(_, Ok(True))
+
+ False
+ |> from
+ |> bool
+ |> expect:equal(_, Ok(False))
+
+ 1
+ |> from
+ |> bool
+ |> expect:equal(_, Error("Expected a Bool, got `1`"))
+
+ []
+ |> from
+ |> bool
+ |> expect:equal(_, Error("Expected a Bool, got `[]`"))
+}
+
+pub external fn thunk(Any) -> Result(fn() -> Any, String)
+ = "gleam__stdlib" "thunk"
+
+//// test thunk {
+//// let _ = fn() { 1 }
+//// |> from
+//// |> thunk
+//// |> expect:is_ok
+
+//// let _ = fn(x) { x }
+//// |> from
+//// |> thunk
+//// |> expect:is_error
+
+//// let _ = 1
+//// |> from
+//// |> thunk
+//// |> expect:is_error
+
+//// []
+//// |> from
+//// |> thunk
+//// |> expect:is_error
+//// }
+
+// external fn list_any(Any) -> Result(List(Any), String) = "gleam__stdlib" "decode_list"
+
+// fn list_module() {
+// list
+// }
+
+// pub fn list(any, decode) {
+// any
+// |> list_any
+// |> result:then(_, fn(x) { list_module():traverse(x, decode) })
+// }
+
+//// test list {
+//// let _ = []
+//// |> from
+//// |> list(string)
+//// |> expect:equal(_, Ok([]))
+
+//// let _ = []
+//// |> from
+//// |> list(atom)
+//// |> expect:equal(_, Ok([]))
+
+//// let _ = [1, 2, 3]
+//// |> from
+//// |> list(int)
+//// |> expect:equal(_, Ok([1, 2, 3]))
+
+//// let _ = [[1], [2], [3]]
+//// |> from
+//// |> list(list(int))
+//// |> expect:equal(_, Ok([1, 2, 3]))
+
+//// let _ = 1
+//// |> from
+//// |> list(string)
+//// |> expect:is_error
+
+//// let _ = 1.0
+//// |> from()
+//// |> list(int)
+//// |> expect:is_error
+
+//// let _ = [""]
+//// |> from()
+//// |> list(int)
+//// |> expect:is_error
+
+//// [from(1), any:from("not an int")]
+//// |> from
+//// |> list(int)
+//// |> expect:is_error
+//// }
+
+pub external fn tuple(Any) -> Result({Any, Any}, String)
+ = "gleam__stdlib" "decode_tuple"
+
+test tuple {
+ {1, []}
+ |> from
+ |> tuple
+ |> expect:equal(_, Ok({from(1), from([])}))
+
+ {"ok", "ok"}
+ |> from
+ |> tuple
+ |> expect:equal(_, Ok({from("ok"), from("ok")}))
+
+ {1}
+ |> from
+ |> tuple
+ |> expect:is_error
+
+ {1, 2, 3}
+ |> from
+ |> tuple
+ |> expect:is_error
+
+// {1, 2.0}
+// |> from
+// |> tuple
+// |> result:map(_, fn(x) {
+// let {a, b} = x
+// a |> int |> result:map(_, fn(x) { {x, b} })
+// })
+// // |> result:then(_, fn(x) {
+// // let {a, b} = x
+// // b |> float |> result:map(_, fn(x) { {a, x} })
+// // })
+// // |> expect:equal(_, Ok({1, 2.0}))
+}
+
+////// TODO: FIXME: This doesn't work anymore because atoms are no longer a thing.
+////// "Decode a field from a map, extracting a specified field.
+//////
+////// Multiple fields can be extracted and stored in a new record like so:
+//////
+////// Ok(name) <- decode:field(raw_data, \"name\") |> result:then(_, decode:string)
+////// Ok(size) <- decode:field(raw_data, \"size\") |> result:then(_, decode:int)
+////// Ok({ name = name, size = size })
+//////
+////pub external fn field(Any, a) -> Result(String, Any)
+//// = "gleam__stdlib" "field"
+
+////test field {
+//// let _ = {ok = 1}
+//// |> from
+//// |> field("ok")
+//// |> expect:equal(from(1))
+
+//// let _ = {earlier = 2, ok = 3}
+//// |> from
+//// |> field("ok")
+//// |> expect:equal(from(3))
+
+//// let _ = {}
+//// |> from
+//// |> field("ok")
+//// |> expect:is_error
+
+//// let _ = 1
+//// |> from
+//// |> field("ok")
+//// |> expect:is_error
+
+//// []
+//// |> from
+//// |> field("ok")
+//// |> expect:is_error
+////}
diff --git a/src/gleam__stdlib.erl b/src/gleam__stdlib.erl
index 24668a7..f377e3f 100644
--- a/src/gleam__stdlib.erl
+++ b/src/gleam__stdlib.erl
@@ -1,9 +1,12 @@
-module(gleam__stdlib).
-include_lib("eunit/include/eunit.hrl").
--export([expect_equal/2, expect_not_equal/2, expect_true/1, expect_false/1, expect_is_ok/1,
- expect_is_error/1, atom_from_string/1, atom_create_from_string/1, atom_to_string/1,
- map_fetch/2, iodata_append/2, iodata_prepend/2, identity/1]).
+-export([expect_equal/2, expect_not_equal/2, expect_true/1, expect_false/1,
+ expect_is_ok/1, expect_is_error/1, atom_from_string/1,
+ atom_create_from_string/1, atom_to_string/1, map_fetch/2,
+ iodata_append/2, iodata_prepend/2, identity/1, decode_int/1,
+ decode_string/1, decode_bool/1, decode_float/1, decode_thunk/1,
+ decode_tuple/1, decode_field/2]).
expect_equal(A, Expected) -> ?assertEqual(Expected, A).
expect_not_equal(A, Expected) -> ?assertNotEqual(Expected, A).
@@ -33,3 +36,33 @@ iodata_append(Iodata, String) -> [Iodata, String].
iodata_prepend(Iodata, String) -> [String, Iodata].
identity(X) -> X.
+
+decode_error_msg(Type, Data) ->
+ {error, iolist_to_binary(io_lib:format("Expected ~s, got `~p`", [Type, Data]))}.
+
+decode_string(Data) when is_binary(Data) -> {ok, Data};
+decode_string(Data) -> decode_error_msg("a String", Data).
+
+decode_int(Data) when is_integer(Data) -> {ok, Data};
+decode_int(Data) -> decode_error_msg("an Int", Data).
+
+decode_float(Data) when is_float(Data) -> {ok, Data};
+decode_float(Data) -> decode_error_msg("a Float", Data).
+
+decode_bool(Data) when is_boolean(Data) -> {ok, Data};
+decode_bool(Data) -> decode_error_msg("a Bool", Data).
+
+decode_thunk(Data) when is_function(Data, 0) -> {ok, Data};
+decode_thunk(Data) -> decode_error_msg("a zero arity function", Data).
+
+decode_tuple(Data = {_, _}) -> {ok, Data};
+decode_tuple(Data) -> decode_error_msg("a 2 element tuple", Data).
+
+decode_field(Data, Key) ->
+ case Data of
+ #{Key := Value} ->
+ {ok, Value};
+
+ _ ->
+ decode_error_msg(io_lib:format("a map with key `~p`", [Key]), Data)
+ end.
diff --git a/src/result.gleam b/src/result.gleam
index 113925e..18503ec 100644
--- a/src/result.gleam
+++ b/src/result.gleam
@@ -2,11 +2,6 @@ import expect
// Result represents the result of something that may succeed or fail.
// `Ok` means it was successful, `Error` means it failed.
-//
-pub enum Result(error, value) =
- | Ok(value)
- | Error(error)
-;
pub fn is_ok(result) {
case result {
@@ -38,7 +33,7 @@ test is_error {
pub fn map(result, fun) {
case result {
| Ok(x) -> Ok(fun(x))
- | Error(_) -> result
+ | Error(e) -> Error(e)
}
}
@@ -47,6 +42,10 @@ test map {
|> map(_, fn(x) { x + 1 })
|> expect:equal(_, Ok(2))
+ Ok(1)
+ |> map(_, fn(_) { "2" })
+ |> expect:equal(_, Ok("2"))
+
Error(1)
|> map(_, fn(x) { x + 1 })
|> expect:equal(_, Error(1))
@@ -90,7 +89,7 @@ test flatten {
|> expect:equal(_, Error(Error(1)))
}
-pub fn flat_map(result, fun) {
+pub fn then(result, fun) {
case result {
| Ok(x) ->
case fun(x) {
@@ -101,17 +100,17 @@ pub fn flat_map(result, fun) {
}
}
-test flat_map {
+test then {
Error(1)
- |> flat_map(_, fn(x) { Ok(x + 1) })
+ |> then(_, fn(x) { Ok(x + 1) })
|> expect:equal(_, Error(1))
Ok(1)
- |> flat_map(_, fn(x) { Ok(x + 1) })
+ |> then(_, fn(x) { Ok(x + 1) })
|> expect:equal(_, Ok(2))
Ok(1)
- |> flat_map(_, fn(_) { Error(1) })
+ |> then(_, fn(_) { Error(1) })
|> expect:equal(_, Error(1))
}