Skip to content

Commit

Permalink
Rewrite internals to combine decoders
Browse files Browse the repository at this point in the history
  • Loading branch information
mlms13 committed May 25, 2019
1 parent 7c607c4 commit 4ac5549
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 46 deletions.
79 changes: 36 additions & 43 deletions src/DecodeBase.re
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,17 @@ module DecodeBase = (T: TransformError, M: MONAD with type t('a) = T.t('a)) => {

let string = value(Js.Json.decodeString, `ExpectedString);

let floatFromNumber = json =>
value(Js.Json.decodeNumber, `ExpectedNumber, json);
let floatFromNumber = value(Js.Json.decodeNumber, `ExpectedNumber);

[@ocaml.deprecated "Use floatFromNumber instead."]
let float = floatFromNumber;

let intFromNumber = json => {
let intFromNumber = {
let isInt = v => v == 0.0 || mod_float(v, floor(v)) == 0.0;
floatFromNumber(json)
|> M.flat_map(_, v =>
isInt(v) ? M.pure(int_of_float(v)) : T.valErr(`ExpectedInt, json)
);
flatMap(
v => isInt(v) ? pure(int_of_float(v)) : T.valErr(`ExpectedInt),
floatFromNumber,
);
};

[@ocaml.deprecated "Use intFromNumber instead."]
Expand All @@ -108,13 +107,10 @@ module DecodeBase = (T: TransformError, M: MONAD with type t('a) = T.t('a)) => {
alt(fromFloat, fromString) |> flatMap(isValid);
};

let variantFromJson = (jsonToJs, jsToVariant, json) =>
jsonToJs(json)
|> M.map(jsToVariant)
|> M.flat_map(
_,
Option.foldLazy(() => T.valErr(`ExpectedValidOption, json), M.pure),
);
let variantFromJson = (jsonToJs, jsToVariant) =>
jsonToJs
|> map(jsToVariant)
|> flatMap(Option.foldLazy(() => T.valErr(`ExpectedValidOption), pure));

let variantFromString = (stringToVariant, json) =>
variantFromJson(string, stringToVariant, json);
Expand All @@ -124,43 +120,41 @@ module DecodeBase = (T: TransformError, M: MONAD with type t('a) = T.t('a)) => {

let optional = (decode, json) =>
switch (Js.Json.decodeNull(json)) {
| Some(_) => M.pure(None)
| None => decode(json) |> M.map(v => Some(v))
| Some(_) => pure(None, json)
| None => map(v => Some(v), decode, json)
};

let array = (decode, json) => {
let decodeEach = arr =>
let array = decode => {
let decodeEach =
Array.foldLeft(
((pos, acc), curr) => {
let decoded = T.arrErr(pos, decode(curr));
let result = InnerApply.map2(flip(Array.append), acc, decoded);
let decoded = _ => T.arrErr(pos, decode(curr));
let result = map2(flip(Array.append), acc, decoded);
(pos + 1, result);
},
(0, M.pure([||])),
arr,
(0, pure([||])),
);

value(Js.Json.decodeArray, `ExpectedArray, json)
|> M.flat_map(_, decodeEach >> snd);
value(Js.Json.decodeArray, `ExpectedArray) |> flatMap(decodeEach >> snd);
};

let list = (decode, json) => array(decode, json) |> M.map(Array.toList);
let list = decode => array(decode) |> map(Array.toList);

let dict = (decode, json) => {
let dict = decode => {
let rec decodeEntries =
fun
| [] => M.pure([])
| [] => pure([])
| [(key, value), ...xs] =>
InnerApply.map2(
map2(
(decodedValue, rest) => [(key, decodedValue), ...rest],
T.objErr(key, decode(value)),
_ => T.objErr(key, decode(value)),
decodeEntries(xs),
);

value(Js.Json.decodeObject, `ExpectedObject, json)
|> M.map(Js.Dict.entries >> Array.toList)
|> M.flat_map(_, decodeEntries)
|> M.map(Js.Dict.fromList);
value(Js.Json.decodeObject, `ExpectedObject)
|> map(Js.Dict.entries >> Array.toList)
|> flatMap(decodeEntries)
|> map(Js.Dict.fromList);
};

let rec at = (fields, decode) =>
Expand All @@ -173,16 +167,15 @@ module DecodeBase = (T: TransformError, M: MONAD with type t('a) = T.t('a)) => {
|> flatMap(at(xs, decode) >> T.objErr(x) >> const)
};

let field = (name, decode, json) => at([name], decode, json);
let field = (name, decode) => at([name], decode);

let optionalField = (name, decode, json) =>
value(Js.Json.decodeObject, `ExpectedObject, json)
|> M.map(Js.Dict.get(_, name))
|> M.flat_map(_, opt =>
switch (opt) {
| None => M.pure(None)
| Some(v) => optional(decode, v)
}
let optionalField = (name, decode) =>
value(Js.Json.decodeObject, `ExpectedObject)
|> map(Js.Dict.get(_, name))
|> flatMap(
fun
| None => pure(None)
| Some(v) => (_ => optional(decode, v)),
);

let fallback = (name, decode, recovery) =>
Expand All @@ -202,7 +195,7 @@ module DecodeBase = (T: TransformError, M: MONAD with type t('a) = T.t('a)) => {
* `succeed` returns a `json => Result` decode function that ignores the `json`
* argument and always returns `Ok`
*/
let succeed = (v, _) => M.pure(v);
let succeed = pure;

let pipe = (a, b, json) => map2((|>), a, b, json);

Expand Down
2 changes: 1 addition & 1 deletion src/Decode_AsOption.rei
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ let oneOf:
option('a);

module Pipeline: {
let succeed: ('a, 'b) => option('a);
let succeed: ('a, Js.Json.t) => option('a);

let field:
(
Expand Down
3 changes: 2 additions & 1 deletion src/Decode_AsResult_OfParseError.rei
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ let oneOf:
Belt.Result.t('a, Decode_ParseError.failure);

module Pipeline: {
let succeed: ('a, 'b) => Belt.Result.t('a, Decode_ParseError.failure);
let succeed:
('a, Js.Json.t) => Belt.Result.t('a, Decode_ParseError.failure);

let field:
(
Expand Down
2 changes: 1 addition & 1 deletion src/Decode_AsResult_OfStringNel.rei
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ let oneOf:
Belt.Result.t('a, NonEmptyList.t(string));

module Pipeline: {
let succeed: ('a, 'b) => Belt.Result.t('a, NonEmptyList.t(string));
let succeed: ('a, Js.Json.t) => Belt.Result.t('a, NonEmptyList.t(string));

let field:
(
Expand Down

0 comments on commit 4ac5549

Please sign in to comment.