mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
merge builtin-json
This commit is contained in:
commit
ef0de4c72f
48 changed files with 1175 additions and 977 deletions
|
@ -188,6 +188,23 @@ pub const RocList = extern struct {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn allocateExact(
|
||||
alignment: u32,
|
||||
length: usize,
|
||||
element_width: usize,
|
||||
) RocList {
|
||||
if (length == 0) {
|
||||
return empty();
|
||||
}
|
||||
|
||||
const data_bytes = length * element_width;
|
||||
return RocList{
|
||||
.bytes = utils.allocateWithRefcount(data_bytes, alignment),
|
||||
.length = length,
|
||||
.capacity_or_ref_ptr = length,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn reallocate(
|
||||
self: RocList,
|
||||
alignment: u32,
|
||||
|
@ -474,6 +491,30 @@ pub fn listReserve(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn listReleaseExcessCapacity(
|
||||
list: RocList,
|
||||
alignment: u32,
|
||||
element_width: usize,
|
||||
update_mode: UpdateMode,
|
||||
) callconv(.C) RocList {
|
||||
const old_length = list.len();
|
||||
// We use the direct list.capacity_or_ref_ptr to make sure both that there is no extra capacity and that it isn't a seamless slice.
|
||||
if ((update_mode == .InPlace or list.isUnique()) and list.capacity_or_ref_ptr == old_length) {
|
||||
return list;
|
||||
} else if (old_length == 0) {
|
||||
list.decref(alignment);
|
||||
return RocList.empty();
|
||||
} else {
|
||||
var output = RocList.allocateExact(alignment, old_length, element_width);
|
||||
if (list.bytes) |source_ptr| {
|
||||
const dest_ptr = output.bytes orelse unreachable;
|
||||
|
||||
@memcpy(dest_ptr, source_ptr, old_length * element_width);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listAppendUnsafe(
|
||||
list: RocList,
|
||||
element: Opaque,
|
||||
|
|
|
@ -56,6 +56,7 @@ comptime {
|
|||
exportListFn(list.listIsUnique, "is_unique");
|
||||
exportListFn(list.listCapacity, "capacity");
|
||||
exportListFn(list.listRefcountPtr, "refcount_ptr");
|
||||
exportListFn(list.listReleaseExcessCapacity, "release_excess_capacity");
|
||||
}
|
||||
|
||||
// Num Module
|
||||
|
|
|
@ -1,3 +1,40 @@
|
|||
## JSON is a data format that is easy for humans to read and write. It is
|
||||
## commonly used to exhange data between two systems such as a server and a
|
||||
## client (e.g. web browser).
|
||||
##
|
||||
## This module implements functionality to serialise and de-serialise Roc types
|
||||
## to and from JSON data. Using the `Encode` and `Decode` builtins this process
|
||||
## can be achieved without the need to write custom encoder and decoder functions
|
||||
## to parse UTF-8 strings.
|
||||
##
|
||||
## Here is a basic example which shows how to parse a JSON record into a Roc
|
||||
## type named `Language` which includes a `name` field. The JSON string is
|
||||
## decoded and then the field is encoded back into a UTF-8 string.
|
||||
##
|
||||
## ```
|
||||
## Language : {
|
||||
## name : Str,
|
||||
## }
|
||||
##
|
||||
## jsonStr = Str.toUtf8 "{\"name\":\"Röc Lang\"}"
|
||||
##
|
||||
## result : Result Language _
|
||||
## result =
|
||||
## jsonStr
|
||||
## |> Decode.fromBytes fromUtf8 # returns `Ok {name : "Röc Lang"}`
|
||||
##
|
||||
## name =
|
||||
## decodedValue <- Result.map result
|
||||
##
|
||||
## Encode.toBytes decodedValue.name toUtf8
|
||||
##
|
||||
## expect name == Ok (Str.toUtf8 "\"Röc Lang\"")
|
||||
## ```
|
||||
##
|
||||
## **Note:** This module is likely to be moved out of the builtins in future.
|
||||
## It is currently located here to facilitate development of the Abilities
|
||||
## language feature and testing. You are welcome to use this module, just note
|
||||
## that it will be moved into a package in a future update.
|
||||
interface Json
|
||||
exposes [
|
||||
Json,
|
||||
|
@ -7,6 +44,7 @@ interface Json
|
|||
imports [
|
||||
List,
|
||||
Str,
|
||||
Result.{ Result },
|
||||
Encode,
|
||||
Encode.{
|
||||
Encoder,
|
||||
|
@ -37,10 +75,8 @@ interface Json
|
|||
Result,
|
||||
]
|
||||
|
||||
## **Note:** This module is likely to be moved out of the builtins in future.
|
||||
## It is currently located here to facilitate development of the Abilities
|
||||
## language feature and testing. You are welcome to use this module, just note
|
||||
## that it will be moved into a package in a future update.
|
||||
## An opaque type with the `EncoderFormatting` and
|
||||
## `DecoderFormatting` abilities.
|
||||
Json := {} has [
|
||||
EncoderFormatting {
|
||||
u8: encodeU8,
|
||||
|
@ -83,8 +119,10 @@ Json := {} has [
|
|||
},
|
||||
]
|
||||
|
||||
## Returns a JSON `Decoder`
|
||||
toUtf8 = @Json {}
|
||||
|
||||
## Returns a JSON `Encoder`
|
||||
fromUtf8 = @Json {}
|
||||
|
||||
numToBytes = \n ->
|
||||
|
@ -402,12 +440,18 @@ decodeList = \decodeElem -> Decode.custom \bytes, @Json {} ->
|
|||
when bytes is
|
||||
['[', ']'] -> { result: Ok [], rest: List.drop bytes 2 }
|
||||
['[', ..] ->
|
||||
when decodeElems (eatWhitespace (List.dropFirst bytes)) [] is
|
||||
Errored e rest -> { result: Err e, rest }
|
||||
Done vals rest ->
|
||||
when rest is
|
||||
[']', ..] -> { result: Ok vals, rest: List.dropFirst rest }
|
||||
_ -> { result: Err TooShort, rest }
|
||||
bytesWithoutWhitespace = eatWhitespace (List.dropFirst bytes)
|
||||
when bytesWithoutWhitespace is
|
||||
[']', ..] ->
|
||||
{ result: Ok [], rest: List.dropFirst bytesWithoutWhitespace }
|
||||
_ ->
|
||||
when decodeElems bytesWithoutWhitespace [] is
|
||||
Errored e rest ->
|
||||
{ result: Err e, rest }
|
||||
Done vals rest ->
|
||||
when rest is
|
||||
[']', ..] -> { result: Ok vals, rest: List.dropFirst rest }
|
||||
_ -> { result: Err TooShort, rest }
|
||||
|
||||
_ ->
|
||||
{ result: Err TooShort, rest: bytes }
|
||||
|
@ -495,6 +539,7 @@ expect
|
|||
input = Str.toUtf8 " \n\r\tabc"
|
||||
actual = eatWhitespace input
|
||||
expected = Str.toUtf8 "abc"
|
||||
|
||||
actual == expected
|
||||
|
||||
# Test json string decoding with escapes
|
||||
|
@ -502,6 +547,7 @@ expect
|
|||
input = Str.toUtf8 "\"a\r\nbc\\\"xz\""
|
||||
expected = Ok "a\r\nbc\\\"xz"
|
||||
actual = Decode.fromBytes input fromUtf8
|
||||
|
||||
actual == expected
|
||||
|
||||
# Test json string encoding with escapes
|
||||
|
@ -509,53 +555,31 @@ expect
|
|||
input = "a\r\nbc\\\"xz"
|
||||
expected = Str.toUtf8 "\"a\r\nbc\\\"xz\""
|
||||
actual = Encode.toBytes input toUtf8
|
||||
|
||||
actual == expected
|
||||
|
||||
# Test json array decode empty list
|
||||
expect
|
||||
input = Str.toUtf8 "[ ]"
|
||||
expected = []
|
||||
|
||||
actual : List U8
|
||||
actual = Decode.fromBytes input fromUtf8 |> Result.withDefault []
|
||||
actual : Result (List U8) _
|
||||
actual = Decode.fromBytes input fromUtf8
|
||||
expected = Ok []
|
||||
|
||||
actual == expected
|
||||
|
||||
# Test json array decoding into integers
|
||||
expect
|
||||
input = Str.toUtf8 "[ 1,\n2,\t3]"
|
||||
expected = [1, 2, 3]
|
||||
|
||||
actual : List U8
|
||||
actual = Decode.fromBytes input fromUtf8 |> Result.withDefault []
|
||||
actual : Result (List U8) _
|
||||
actual = Decode.fromBytes input fromUtf8
|
||||
expected = Ok [1, 2, 3]
|
||||
|
||||
actual == expected
|
||||
|
||||
# Test json array decoding into strings ignoring whitespace around values
|
||||
expect
|
||||
input = Str.toUtf8 "[\r\"one\" ,\t\"two\"\n,\n\"3\"\t]"
|
||||
expected = ["one", "two", "3"]
|
||||
|
||||
actual : List Str
|
||||
actual =
|
||||
Decode.fromBytes input fromUtf8
|
||||
|> Result.onErr handleJsonDecodeError
|
||||
|> Result.withDefault []
|
||||
actual = Decode.fromBytes input fromUtf8
|
||||
expected = Ok ["one", "two", "3"]
|
||||
|
||||
actual == expected
|
||||
|
||||
# Helper for tests to handle Json decoding errors
|
||||
handleJsonDecodeError = \err ->
|
||||
when err is
|
||||
Leftover bytes ->
|
||||
when Str.fromUtf8 bytes is
|
||||
Ok bs -> crash "ERROR: bytes left \(bs)"
|
||||
Err _ ->
|
||||
ls =
|
||||
bytes
|
||||
|> List.map Num.toStr
|
||||
|> Str.joinWith ","
|
||||
|
||||
crash "ERROR: bytes left \(ls)"
|
||||
|
||||
TooShort -> crash "ERROR: input too short"
|
||||
|
|
|
@ -62,6 +62,7 @@ interface List
|
|||
sortAsc,
|
||||
sortDesc,
|
||||
reserve,
|
||||
releaseExcessCapacity,
|
||||
walkBackwardsUntil,
|
||||
countIf,
|
||||
]
|
||||
|
@ -291,6 +292,10 @@ withCapacity : Nat -> List a
|
|||
## Enlarge the list for at least capacity additional elements
|
||||
reserve : List a, Nat -> List a
|
||||
|
||||
## Shrink the memory footprint of a list such that it's capacity and length are equal.
|
||||
## Note: This will also convert seamless slices to regular lists.
|
||||
releaseExcessCapacity : List a -> List a
|
||||
|
||||
## Put two lists together.
|
||||
## ```
|
||||
## List.concat [1, 2, 3] [4, 5]
|
||||
|
|
|
@ -352,6 +352,7 @@ pub const LIST_APPEND_UNSAFE: &str = "roc_builtins.list.append_unsafe";
|
|||
pub const LIST_RESERVE: &str = "roc_builtins.list.reserve";
|
||||
pub const LIST_CAPACITY: &str = "roc_builtins.list.capacity";
|
||||
pub const LIST_REFCOUNT_PTR: &str = "roc_builtins.list.refcount_ptr";
|
||||
pub const LIST_RELEASE_EXCESS_CAPACITY: &str = "roc_builtins.list.release_excess_capacity";
|
||||
|
||||
pub const DEC_FROM_STR: &str = "roc_builtins.dec.from_str";
|
||||
pub const DEC_TO_STR: &str = "roc_builtins.dec.to_str";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue