Packages
gleam_stdlib
0.57.0
1.0.3
1.0.2
1.0.1
1.0.0
0.71.0
0.70.0
0.69.0
0.68.1
0.68.0
0.67.1
0.67.0
0.65.0
0.64.0
0.63.2
0.63.1
0.63.0
0.62.1
0.62.0
0.61.0
0.60.0
0.59.0
0.58.0
0.57.0
0.56.0
0.55.0
0.54.0
0.53.0
0.52.0
0.51.0
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.0
0.42.0
0.41.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.1
0.35.0
0.34.0
0.33.1
0.33.0
0.32.1
0.32.0
0.31.0
0.30.2
0.30.1
0.30.0
0.29.2
0.29.1
0.29.0
0.28.2
0.28.1
0.28.0
0.27.0
0.26.1
0.26.0
0.25.0
0.24.0
0.23.0
0.22.3
0.22.2
0.22.1
0.22.0
0.21.0
0.20.0
0.19.3
0.19.2
0.19.1
0.19.0
0.18.1
0.18.0
0.18.0-rc1
0.17.1
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.1
0.10.0
0.9.0
0.8.0
0.7.0
0.6.0
0.5.0
0.4.0
0.4.0-rc1
0.3.1
0.3.0
0.2.0
retired
A standard library for the Gleam programming language
Current section
Files
Jump to
Current section
Files
src/gleam/dynamic.gleam
import gleam/bit_array as bit_array_mod
import gleam/dict.{type Dict}
import gleam/int as int_mod
import gleam/list as list_mod
import gleam/option.{type Option, Some}
import gleam/result as result_mod
import gleam/string_tree
/// `Dynamic` 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.
///
pub type Dynamic
/// Return a string indicating the type of the dynamic value.
///
/// This function may be useful for constructing error messages or logs. If you
/// want to turn dynamic data into well typed data then you want the
/// `gleam/dynamic/decode` module.
///
/// ```gleam
/// classify(from("Hello"))
/// // -> "String"
/// ```
///
@external(erlang, "gleam_stdlib", "classify_dynamic")
@external(javascript, "../gleam_stdlib.mjs", "classify_dynamic")
pub fn classify(data: Dynamic) -> String
pub type DecodeError {
DecodeError(expected: String, found: String, path: List(String))
}
pub type DecodeErrors =
List(DecodeError)
pub type Decoder(t) =
fn(Dynamic) -> Result(t, DecodeErrors)
/// Converts any Gleam data into `Dynamic` data.
///
@external(erlang, "gleam_stdlib", "identity")
@external(javascript, "../gleam_stdlib.mjs", "identity")
pub fn from(a: anything) -> Dynamic
@deprecated("Please use the gleam/dynamic/decode module")
pub fn dynamic(value: Dynamic) -> Result(Dynamic, List(DecodeError)) {
Ok(value)
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn bit_array(from data: Dynamic) -> Result(BitArray, DecodeErrors) {
decode_bit_array(data)
}
@external(erlang, "gleam_stdlib", "decode_bit_array")
@external(javascript, "../gleam_stdlib.mjs", "decode_bit_array")
fn decode_bit_array(a: Dynamic) -> Result(BitArray, DecodeErrors)
@deprecated("Please use the gleam/dynamic/decode module")
pub fn string(from data: Dynamic) -> Result(String, DecodeErrors) {
decode_string(data)
}
@external(javascript, "../gleam_stdlib.mjs", "decode_string")
fn decode_string(from data: Dynamic) -> Result(String, DecodeErrors) {
decode_bit_array(data)
|> map_errors(put_expected(_, "String"))
|> result_mod.try(fn(raw) {
case bit_array_mod.to_string(raw) {
Ok(string) -> Ok(string)
Error(Nil) ->
Error([DecodeError(expected: "String", found: "BitArray", path: [])])
}
})
}
fn map_errors(
result: Result(a, DecodeErrors),
f: fn(DecodeError) -> DecodeError,
) -> Result(a, DecodeErrors) {
result_mod.map_error(result, list_mod.map(_, f))
}
fn put_expected(error: DecodeError, expected: String) -> DecodeError {
DecodeError(..error, expected: expected)
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn int(from data: Dynamic) -> Result(Int, DecodeErrors) {
decode_int(data)
}
@external(erlang, "gleam_stdlib", "decode_int")
@external(javascript, "../gleam_stdlib.mjs", "decode_int")
fn decode_int(a: Dynamic) -> Result(Int, DecodeErrors)
@deprecated("Please use the gleam/dynamic/decode module")
pub fn float(from data: Dynamic) -> Result(Float, DecodeErrors) {
decode_float(data)
}
@external(erlang, "gleam_stdlib", "decode_float")
@external(javascript, "../gleam_stdlib.mjs", "decode_float")
fn decode_float(a: Dynamic) -> Result(Float, DecodeErrors)
@deprecated("Please use the gleam/dynamic/decode module")
pub fn bool(from data: Dynamic) -> Result(Bool, DecodeErrors) {
decode_bool(data)
}
@external(erlang, "gleam_stdlib", "decode_bool")
@external(javascript, "../gleam_stdlib.mjs", "decode_bool")
fn decode_bool(a: Dynamic) -> Result(Bool, DecodeErrors)
@deprecated("Please use the gleam/dynamic/decode module")
pub fn shallow_list(from value: Dynamic) -> Result(List(Dynamic), DecodeErrors) {
decode_list(value)
}
@external(erlang, "gleam_stdlib", "decode_list")
@external(javascript, "../gleam_stdlib.mjs", "decode_list")
fn decode_list(a: Dynamic) -> Result(List(Dynamic), DecodeErrors)
@deprecated("Please use the gleam/dynamic/decode module")
pub fn result(
ok decode_ok: Decoder(a),
error decode_error: Decoder(e),
) -> Decoder(Result(a, e)) {
fn(value) {
use inner_result <- result_mod.try(decode_result(value))
case inner_result {
Ok(raw) -> {
use value <- result_mod.try(
decode_ok(raw)
|> map_errors(push_path(_, "ok")),
)
Ok(Ok(value))
}
Error(raw) -> {
use value <- result_mod.try(
decode_error(raw)
|> map_errors(push_path(_, "error")),
)
Ok(Error(value))
}
}
}
}
@external(erlang, "gleam_stdlib", "decode_result")
@external(javascript, "../gleam_stdlib.mjs", "decode_result")
fn decode_result(a: Dynamic) -> Result(Result(a, e), DecodeErrors)
@deprecated("Please use the gleam/dynamic/decode module")
pub fn list(
of decoder_type: fn(Dynamic) -> Result(inner, DecodeErrors),
) -> Decoder(List(inner)) {
fn(dynamic) {
use list <- result_mod.try(decode_list(dynamic))
list
|> list_mod.try_map(decoder_type)
|> map_errors(push_path(_, "*"))
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn optional(of decode: Decoder(inner)) -> Decoder(Option(inner)) {
fn(value) { decode_optional(value, decode) }
}
@external(erlang, "gleam_stdlib", "decode_option")
@external(javascript, "../gleam_stdlib.mjs", "decode_option")
fn decode_optional(a: Dynamic, b: Decoder(a)) -> Result(Option(a), DecodeErrors)
@deprecated("Please use the gleam/dynamic/decode module")
pub fn field(named name: a, of inner_type: Decoder(t)) -> Decoder(t) {
fn(value) {
let missing_field_error =
DecodeError(expected: "field", found: "nothing", path: [])
use maybe_inner <- result_mod.try(decode_field(value, name))
maybe_inner
|> option.to_result([missing_field_error])
|> result_mod.try(inner_type)
|> map_errors(push_path(_, name))
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn optional_field(
named name: a,
of inner_type: Decoder(t),
) -> Decoder(Option(t)) {
fn(value) {
use maybe_inner <- result_mod.try(decode_field(value, name))
case maybe_inner {
option.None -> Ok(option.None)
option.Some(dynamic_inner) ->
inner_type(dynamic_inner)
|> result_mod.map(Some)
|> map_errors(push_path(_, name))
}
}
}
@external(erlang, "gleam_stdlib", "decode_field")
@external(javascript, "../gleam_stdlib.mjs", "decode_field")
fn decode_field(a: Dynamic, b: name) -> Result(Option(Dynamic), DecodeErrors)
@deprecated("Please use the gleam/dynamic/decode module")
pub fn element(at index: Int, of inner_type: Decoder(inner)) -> Decoder(inner) {
fn(data: Dynamic) {
use tuple <- result_mod.try(decode_tuple(data))
let size = tuple_size(tuple)
use data <- result_mod.try(case index >= 0 {
True ->
case index < size {
True -> tuple_get(tuple, index)
False -> at_least_decode_tuple_error(index + 1, data)
}
False ->
case int_mod.absolute_value(index) <= size {
True -> tuple_get(tuple, size + index)
False ->
at_least_decode_tuple_error(int_mod.absolute_value(index), data)
}
})
inner_type(data)
|> map_errors(push_path(_, index))
}
}
fn at_least_decode_tuple_error(
size: Int,
data: Dynamic,
) -> Result(a, DecodeErrors) {
let s = case size {
1 -> ""
_ -> "s"
}
let error =
["Tuple of at least ", int_mod.to_string(size), " element", s]
|> string_tree.from_strings
|> string_tree.to_string
|> DecodeError(found: classify(data), path: [])
Error([error])
}
// A tuple of unknown size
type UnknownTuple
@external(erlang, "gleam_stdlib", "decode_tuple")
@external(javascript, "../gleam_stdlib.mjs", "decode_tuple")
fn decode_tuple(a: Dynamic) -> Result(UnknownTuple, DecodeErrors)
@external(erlang, "gleam_stdlib", "decode_tuple2")
@external(javascript, "../gleam_stdlib.mjs", "decode_tuple2")
fn decode_tuple2(a: Dynamic) -> Result(#(Dynamic, Dynamic), DecodeErrors)
@external(erlang, "gleam_stdlib", "decode_tuple3")
@external(javascript, "../gleam_stdlib.mjs", "decode_tuple3")
fn decode_tuple3(
a: Dynamic,
) -> Result(#(Dynamic, Dynamic, Dynamic), DecodeErrors)
@external(erlang, "gleam_stdlib", "decode_tuple4")
@external(javascript, "../gleam_stdlib.mjs", "decode_tuple4")
fn decode_tuple4(
a: Dynamic,
) -> Result(#(Dynamic, Dynamic, Dynamic, Dynamic), DecodeErrors)
@external(erlang, "gleam_stdlib", "decode_tuple5")
@external(javascript, "../gleam_stdlib.mjs", "decode_tuple5")
fn decode_tuple5(
a: Dynamic,
) -> Result(#(Dynamic, Dynamic, Dynamic, Dynamic, Dynamic), DecodeErrors)
@external(erlang, "gleam_stdlib", "decode_tuple6")
@external(javascript, "../gleam_stdlib.mjs", "decode_tuple6")
fn decode_tuple6(
a: Dynamic,
) -> Result(
#(Dynamic, Dynamic, Dynamic, Dynamic, Dynamic, Dynamic),
DecodeErrors,
)
@external(erlang, "gleam_stdlib", "tuple_get")
@external(javascript, "../gleam_stdlib.mjs", "tuple_get")
fn tuple_get(a: UnknownTuple, b: Int) -> Result(Dynamic, DecodeErrors)
@external(erlang, "gleam_stdlib", "size_of_tuple")
@external(javascript, "../gleam_stdlib.mjs", "length")
fn tuple_size(a: UnknownTuple) -> Int
fn tuple_errors(
result: Result(a, List(DecodeError)),
name: String,
) -> List(DecodeError) {
case result {
Ok(_) -> []
Error(errors) -> list_mod.map(errors, push_path(_, name))
}
}
fn push_path(error: DecodeError, name: t) -> DecodeError {
let name = from(name)
let decoder =
do_any([
decode_string,
fn(x) { result_mod.map(decode_int(x), int_mod.to_string) },
])
let name = case decoder(name) {
Ok(name) -> name
Error(_) ->
["<", classify(name), ">"]
|> string_tree.from_strings
|> string_tree.to_string
}
DecodeError(..error, path: [name, ..error.path])
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn tuple2(
first decode1: Decoder(a),
second decode2: Decoder(b),
) -> Decoder(#(a, b)) {
fn(value) {
use #(a, b) <- result_mod.try(decode_tuple2(value))
case decode1(a), decode2(b) {
Ok(a), Ok(b) -> Ok(#(a, b))
a, b ->
tuple_errors(a, "0")
|> list_mod.append(tuple_errors(b, "1"))
|> Error
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn tuple3(
first decode1: Decoder(a),
second decode2: Decoder(b),
third decode3: Decoder(c),
) -> Decoder(#(a, b, c)) {
fn(value) {
use #(a, b, c) <- result_mod.try(decode_tuple3(value))
case decode1(a), decode2(b), decode3(c) {
Ok(a), Ok(b), Ok(c) -> Ok(#(a, b, c))
a, b, c ->
tuple_errors(a, "0")
|> list_mod.append(tuple_errors(b, "1"))
|> list_mod.append(tuple_errors(c, "2"))
|> Error
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn tuple4(
first decode1: Decoder(a),
second decode2: Decoder(b),
third decode3: Decoder(c),
fourth decode4: Decoder(d),
) -> Decoder(#(a, b, c, d)) {
fn(value) {
use #(a, b, c, d) <- result_mod.try(decode_tuple4(value))
case decode1(a), decode2(b), decode3(c), decode4(d) {
Ok(a), Ok(b), Ok(c), Ok(d) -> Ok(#(a, b, c, d))
a, b, c, d ->
tuple_errors(a, "0")
|> list_mod.append(tuple_errors(b, "1"))
|> list_mod.append(tuple_errors(c, "2"))
|> list_mod.append(tuple_errors(d, "3"))
|> Error
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn tuple5(
first decode1: Decoder(a),
second decode2: Decoder(b),
third decode3: Decoder(c),
fourth decode4: Decoder(d),
fifth decode5: Decoder(e),
) -> Decoder(#(a, b, c, d, e)) {
fn(value) {
use #(a, b, c, d, e) <- result_mod.try(decode_tuple5(value))
case decode1(a), decode2(b), decode3(c), decode4(d), decode5(e) {
Ok(a), Ok(b), Ok(c), Ok(d), Ok(e) -> Ok(#(a, b, c, d, e))
a, b, c, d, e ->
tuple_errors(a, "0")
|> list_mod.append(tuple_errors(b, "1"))
|> list_mod.append(tuple_errors(c, "2"))
|> list_mod.append(tuple_errors(d, "3"))
|> list_mod.append(tuple_errors(e, "4"))
|> Error
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn tuple6(
first decode1: Decoder(a),
second decode2: Decoder(b),
third decode3: Decoder(c),
fourth decode4: Decoder(d),
fifth decode5: Decoder(e),
sixth decode6: Decoder(f),
) -> Decoder(#(a, b, c, d, e, f)) {
fn(value) {
use #(a, b, c, d, e, f) <- result_mod.try(decode_tuple6(value))
case
decode1(a),
decode2(b),
decode3(c),
decode4(d),
decode5(e),
decode6(f)
{
Ok(a), Ok(b), Ok(c), Ok(d), Ok(e), Ok(f) -> Ok(#(a, b, c, d, e, f))
a, b, c, d, e, f ->
tuple_errors(a, "0")
|> list_mod.append(tuple_errors(b, "1"))
|> list_mod.append(tuple_errors(c, "2"))
|> list_mod.append(tuple_errors(d, "3"))
|> list_mod.append(tuple_errors(e, "4"))
|> list_mod.append(tuple_errors(f, "5"))
|> Error
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn dict(
of key_type: Decoder(k),
to value_type: Decoder(v),
) -> Decoder(Dict(k, v)) {
fn(value) {
use dict <- result_mod.try(decode_dict(value))
use pairs <- result_mod.try(
dict
|> dict.to_list
|> list_mod.try_map(fn(pair) {
let #(k, v) = pair
use k <- result_mod.try(
key_type(k)
|> map_errors(push_path(_, "keys")),
)
use v <- result_mod.try(
value_type(v)
|> map_errors(push_path(_, "values")),
)
Ok(#(k, v))
}),
)
Ok(dict.from_list(pairs))
}
}
@external(erlang, "gleam_stdlib", "decode_map")
@external(javascript, "../gleam_stdlib.mjs", "decode_map")
fn decode_dict(a: Dynamic) -> Result(Dict(Dynamic, Dynamic), DecodeErrors)
@deprecated("Please use the gleam/dynamic/decode module")
pub fn any(of decoders: List(Decoder(a))) -> Decoder(a) {
do_any(decoders)
}
fn do_any(of decoders: List(Decoder(a))) -> Decoder(a) {
fn(data) {
case decoders {
[] ->
Error([
DecodeError(found: classify(data), expected: "another type", path: []),
])
[decoder, ..decoders] ->
case decoder(data) {
Ok(decoded) -> Ok(decoded)
Error(_) -> do_any(decoders)(data)
}
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn decode1(constructor: fn(t1) -> t, t1: Decoder(t1)) -> Decoder(t) {
fn(value) {
case t1(value) {
Ok(a) -> Ok(constructor(a))
a -> Error(all_errors(a))
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn decode2(
constructor: fn(t1, t2) -> t,
t1: Decoder(t1),
t2: Decoder(t2),
) -> Decoder(t) {
fn(value) {
case t1(value), t2(value) {
Ok(a), Ok(b) -> Ok(constructor(a, b))
a, b -> Error(list_mod.flatten([all_errors(a), all_errors(b)]))
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn decode3(
constructor: fn(t1, t2, t3) -> t,
t1: Decoder(t1),
t2: Decoder(t2),
t3: Decoder(t3),
) -> Decoder(t) {
fn(value) {
case t1(value), t2(value), t3(value) {
Ok(a), Ok(b), Ok(c) -> Ok(constructor(a, b, c))
a, b, c ->
Error(list_mod.flatten([all_errors(a), all_errors(b), all_errors(c)]))
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn decode4(
constructor: fn(t1, t2, t3, t4) -> t,
t1: Decoder(t1),
t2: Decoder(t2),
t3: Decoder(t3),
t4: Decoder(t4),
) -> Decoder(t) {
fn(x: Dynamic) {
case t1(x), t2(x), t3(x), t4(x) {
Ok(a), Ok(b), Ok(c), Ok(d) -> Ok(constructor(a, b, c, d))
a, b, c, d ->
Error(
list_mod.flatten([
all_errors(a),
all_errors(b),
all_errors(c),
all_errors(d),
]),
)
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn decode5(
constructor: fn(t1, t2, t3, t4, t5) -> t,
t1: Decoder(t1),
t2: Decoder(t2),
t3: Decoder(t3),
t4: Decoder(t4),
t5: Decoder(t5),
) -> Decoder(t) {
fn(x: Dynamic) {
case t1(x), t2(x), t3(x), t4(x), t5(x) {
Ok(a), Ok(b), Ok(c), Ok(d), Ok(e) -> Ok(constructor(a, b, c, d, e))
a, b, c, d, e ->
Error(
list_mod.flatten([
all_errors(a),
all_errors(b),
all_errors(c),
all_errors(d),
all_errors(e),
]),
)
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn decode6(
constructor: fn(t1, t2, t3, t4, t5, t6) -> t,
t1: Decoder(t1),
t2: Decoder(t2),
t3: Decoder(t3),
t4: Decoder(t4),
t5: Decoder(t5),
t6: Decoder(t6),
) -> Decoder(t) {
fn(x: Dynamic) {
case t1(x), t2(x), t3(x), t4(x), t5(x), t6(x) {
Ok(a), Ok(b), Ok(c), Ok(d), Ok(e), Ok(f) ->
Ok(constructor(a, b, c, d, e, f))
a, b, c, d, e, f ->
Error(
list_mod.flatten([
all_errors(a),
all_errors(b),
all_errors(c),
all_errors(d),
all_errors(e),
all_errors(f),
]),
)
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn decode7(
constructor: fn(t1, t2, t3, t4, t5, t6, t7) -> t,
t1: Decoder(t1),
t2: Decoder(t2),
t3: Decoder(t3),
t4: Decoder(t4),
t5: Decoder(t5),
t6: Decoder(t6),
t7: Decoder(t7),
) -> Decoder(t) {
fn(x: Dynamic) {
case t1(x), t2(x), t3(x), t4(x), t5(x), t6(x), t7(x) {
Ok(a), Ok(b), Ok(c), Ok(d), Ok(e), Ok(f), Ok(g) ->
Ok(constructor(a, b, c, d, e, f, g))
a, b, c, d, e, f, g ->
Error(
list_mod.flatten([
all_errors(a),
all_errors(b),
all_errors(c),
all_errors(d),
all_errors(e),
all_errors(f),
all_errors(g),
]),
)
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn decode8(
constructor: fn(t1, t2, t3, t4, t5, t6, t7, t8) -> t,
t1: Decoder(t1),
t2: Decoder(t2),
t3: Decoder(t3),
t4: Decoder(t4),
t5: Decoder(t5),
t6: Decoder(t6),
t7: Decoder(t7),
t8: Decoder(t8),
) -> Decoder(t) {
fn(x: Dynamic) {
case t1(x), t2(x), t3(x), t4(x), t5(x), t6(x), t7(x), t8(x) {
Ok(a), Ok(b), Ok(c), Ok(d), Ok(e), Ok(f), Ok(g), Ok(h) ->
Ok(constructor(a, b, c, d, e, f, g, h))
a, b, c, d, e, f, g, h ->
Error(
list_mod.flatten([
all_errors(a),
all_errors(b),
all_errors(c),
all_errors(d),
all_errors(e),
all_errors(f),
all_errors(g),
all_errors(h),
]),
)
}
}
}
@deprecated("Please use the gleam/dynamic/decode module")
pub fn decode9(
constructor: fn(t1, t2, t3, t4, t5, t6, t7, t8, t9) -> t,
t1: Decoder(t1),
t2: Decoder(t2),
t3: Decoder(t3),
t4: Decoder(t4),
t5: Decoder(t5),
t6: Decoder(t6),
t7: Decoder(t7),
t8: Decoder(t8),
t9: Decoder(t9),
) -> Decoder(t) {
fn(x: Dynamic) {
case t1(x), t2(x), t3(x), t4(x), t5(x), t6(x), t7(x), t8(x), t9(x) {
Ok(a), Ok(b), Ok(c), Ok(d), Ok(e), Ok(f), Ok(g), Ok(h), Ok(i) ->
Ok(constructor(a, b, c, d, e, f, g, h, i))
a, b, c, d, e, f, g, h, i ->
Error(
list_mod.flatten([
all_errors(a),
all_errors(b),
all_errors(c),
all_errors(d),
all_errors(e),
all_errors(f),
all_errors(g),
all_errors(h),
all_errors(i),
]),
)
}
}
}
fn all_errors(result: Result(a, List(DecodeError))) -> List(DecodeError) {
case result {
Ok(_) -> []
Error(errors) -> errors
}
}