aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLouis Pilfold <louis@lpil.uk>2021-09-09 19:44:35 +0100
committerLouis Pilfold <louis@lpil.uk>2021-09-09 19:44:35 +0100
commitc45c1038f8b12acf7d2010eba070ad3dc54765a2 (patch)
tree39ceed83733a3c54ba4048122a5b4d0b8ce823ed /src
parentc5d415fdc206ae3403b2992c9a3e395188b45280 (diff)
downloadgleam_stdlib-c45c1038f8b12acf7d2010eba070ad3dc54765a2.tar.gz
gleam_stdlib-c45c1038f8b12acf7d2010eba070ad3dc54765a2.zip
JS dynamic string
Diffstat (limited to 'src')
-rw-r--r--src/gleam/dynamic.gleam114
-rw-r--r--src/gleam_stdlib.js23
2 files changed, 100 insertions, 37 deletions
diff --git a/src/gleam/dynamic.gleam b/src/gleam/dynamic.gleam
index 98cbef0..ccc621e 100644
--- a/src/gleam/dynamic.gleam
+++ b/src/gleam/dynamic.gleam
@@ -1,39 +1,66 @@
+import gleam/bit_string
+import gleam/list
+import gleam/map
+import gleam/option
+import gleam/result
+import gleam/string_builder
+
+if erlang {
+ import gleam/map.{Map}
+ import gleam/option.{Option}
+}
+
/// `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 external type Dynamic
-if erlang {
- import gleam/bit_string
- import gleam/list
- import gleam/map.{Map}
- import gleam/option.{Option}
- import gleam/result
- import gleam/string_builder
+/// Error returned when unexpected data is encountered
+pub type DecodeError {
+ DecodeError(expected: String, found: String)
+}
- /// Error returned when unexpected data is encountered
- pub type DecodeError {
- DecodeError(expected: String, found: String)
- }
+pub type Decoder(t) =
+ fn(Dynamic) -> Result(t, DecodeError)
- pub type Decoder(t) =
- fn(Dynamic) -> Result(t, DecodeError)
+/// Converts any Gleam data into `Dynamic` data.
+///
+pub fn from(a) -> Dynamic {
+ do_from(a)
+}
- /// Converts any Gleam data into `Dynamic` data.
- ///
- pub external fn from(a) -> Dynamic =
+if erlang {
+ external fn do_from(anything) -> Dynamic =
"gleam_stdlib" "identity"
+}
- /// Unsafely casts a Dynamic value into any other type.
- ///
- /// This is an escape hatch for the type system that may be useful when wrapping
- /// native Erlang APIs. It is to be used as a last measure only!
- ///
- /// If you can avoid using this function, do!
- ///
- pub external fn unsafe_coerce(Dynamic) -> a =
+if javascript {
+ external fn do_from(anything) -> Dynamic =
+ "../gleam_stdlib.js" "identity"
+}
+
+/// Unsafely casts a Dynamic value into any other type.
+///
+/// This is an escape hatch for the type system that may be useful when wrapping
+/// native Erlang APIs. It is to be used as a last measure only!
+///
+/// If you can avoid using this function, do!
+///
+pub fn unsafe_coerce(a: Dynamic) -> anything {
+ do_unsafe_coerce(a)
+}
+
+if erlang {
+ external fn do_unsafe_coerce(Dynamic) -> a =
"gleam_stdlib" "identity"
+}
+if javascript {
+ external fn do_unsafe_coerce(Dynamic) -> a =
+ "../gleam_stdlib.js" "identity"
+}
+
+if erlang {
/// Checks to see whether a Dynamic value is a bit_string, and return the bit_string if
/// it is.
///
@@ -47,20 +74,26 @@ if erlang {
///
pub external fn bit_string(from: Dynamic) -> Result(BitString, DecodeError) =
"gleam_stdlib" "decode_bit_string"
+}
- /// Checks to see whether a Dynamic value is a string, and return the string if
- /// it is.
- ///
- /// ## Examples
- ///
- /// > string(from("Hello"))
- /// Ok("Hello")
- ///
- /// > string(from(123))
- /// Error(DecodeError(expected: "String", found: "Int"))
- ///
- pub fn string(from: Dynamic) -> Result(String, DecodeError) {
- bit_string(from)
+/// Checks to see whether a Dynamic value is a string, and return the string if
+/// it is.
+///
+/// ## Examples
+///
+/// > string(from("Hello"))
+/// Ok("Hello")
+///
+/// > string(from(123))
+/// Error(DecodeError(expected: "String", found: "Int"))
+///
+pub fn string(from data: Dynamic) -> Result(String, DecodeError) {
+ decode_string(data)
+}
+
+if erlang {
+ fn decode_string(data: Dynamic) -> Result(String, DecodeError) {
+ bit_string(data)
|> result.map_error(fn(error) { DecodeError(..error, expected: "String") })
|> result.then(fn(raw) {
case bit_string.to_string(raw) {
@@ -69,7 +102,14 @@ if erlang {
}
})
}
+}
+if javascript {
+ external fn decode_string(Dynamic) -> Result(String, DecodeError) =
+ "../gleam_stdlib.js" "decode_string"
+}
+
+if erlang {
/// Checks to see whether a Dynamic value is an int, and return the int if it
/// is.
///
diff --git a/src/gleam_stdlib.js b/src/gleam_stdlib.js
index bb63cbb..75b0882 100644
--- a/src/gleam_stdlib.js
+++ b/src/gleam_stdlib.js
@@ -12,6 +12,7 @@ import {
CompileError as RegexCompileError,
Match as RegexMatch,
} from "./gleam/regex.js";
+import { DecodeError } from "./gleam/dynamic.js";
import { Some, None } from "./gleam/option.js";
const HASHCODE_CACHE = new WeakMap();
@@ -467,3 +468,25 @@ export function decode64(sBase64) {
return new Ok(new BitString(taBytes));
}
+
+function classify_dynamic(data) {
+ if (typeof data === "string") {
+ return "String";
+ } else if (List.isList(data)) {
+ return "List";
+ } else if (Number.isInteger(data)) {
+ return "Int";
+ } else {
+ return typeof data;
+ }
+}
+
+function decoder_error(expected, got) {
+ return new Error(new DecodeError(expected, classify_dynamic(got)));
+}
+
+export function decode_string(data) {
+ return typeof data === "string"
+ ? new Ok(data)
+ : decoder_error("String", data);
+}