Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 1 addition & 24 deletions src/Json.flix
Original file line number Diff line number Diff line change
@@ -1,24 +1 @@
mod Json {
use JsonElement.{JsonObject, JsonArray, JsonString, JsonNumber, JsonBool, JsonNull}

pub enum JsonElement {
case JsonObject(Map[String, JsonElement])
case JsonArray(Vector[JsonElement])
case JsonString(String)
case JsonNumber(BigDecimal)
case JsonBool(Bool)
case JsonNull
}

instance Eq[JsonElement] {
pub def eq(x: JsonElement, y: JsonElement): Bool = match (x, y) {
case (JsonObject(a), JsonObject(b)) => a == b
case (JsonArray(a), JsonArray(b)) => a == b
case (JsonString(a), JsonString(b)) => a == b
case (JsonNumber(a), JsonNumber(b)) => a == b
case (JsonBool(a), JsonBool(b)) => a == b
case (JsonNull, JsonNull) => true
case _ => false
}
}
}
pub mod Json {}
208 changes: 6 additions & 202 deletions src/Jsonable.flix → src/Json/FromJson.flix
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
mod Json {
use Json.Path.Path;
use Json.Path.{!!};
use JsonElement.{JsonObject, JsonArray, JsonString, JsonNumber, JsonBool, JsonNull}
use JsonError.JsonError

pub enum JsonError(Path, Set[String]) with Eq

pub trait ToJson[a] {
pub def toJson(x: a): JsonElement
}
pub mod Json.FromJson {
use Json.JsonElement
use Json.JsonElement.{JsonObject, JsonArray, JsonString, JsonNumber, JsonBool, JsonNull}
use Json.JsonError
use Json.Path
use Json.Path.{!!}

pub trait FromJson[a] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, a]
Expand All @@ -22,58 +17,20 @@ mod Json {
pub def fromNullableJson(x: JsonElement): Result[JsonError, Option[a]] = Json.FromJson.fromNullableJsonAt(Path.Root, x)
}

pub lawful trait Jsonable[a] with ToJson[a], FromJson[a] {
law inverse: forall (x: a) with Eq[a] {
x |> Json.ToJson.toJson |> Json.FromJson.fromJson == Ok(x)
}
}

instance ToJson[Bool] {
pub def toJson(x: Bool): JsonElement = JsonBool(x)
}

instance FromJson[Bool] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, Bool] = match x {
case JsonBool(y) => Ok(y)
case _ => Err(JsonError(p, Set#{"boolean value"}))
}
}

instance Jsonable[Bool]

instance ToJson[Char] {
pub def toJson(x: Char): JsonElement = JsonString(Char.toString(x))
}

instance FromJson[Char] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, Char] = match x {
case JsonString(y) if String.length(y) > 0 => Ok(String.charAt(0, y))
case _ => Err(JsonError(p, Set#{"singleton string"}))
}
}

instance Jsonable[Char]

instance ToJson[Float32] {
pub def toJson(x: Float32): JsonElement = {
match Float32.tryToBigDecimal(x) {
case Some(num) => JsonNumber(num)
case None =>
if (Float32.isInfinite(x)) {
if (x > 0.0f32) {
JsonString("Infinity")
} else {
JsonString("-Infinity")
}
} else if (Float32.isNan(x)) {
JsonString("NaN")
} else {
bug!("invalid Float32: ${x}")
}
}
}
}

instance FromJson[Float32] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, Float32] = match x {
case JsonNumber(y) => BigDecimal.tryToFloat32(y) |> Option.toOk(JsonError(p, Set#{"floating-point number", "\"-Infinity\"", "\"Infinity\"", "\"NaN\""}))
Expand All @@ -84,26 +41,6 @@ mod Json {
}
}

instance ToJson[Float64] {
pub def toJson(x: Float64): JsonElement = {
match Float64.tryToBigDecimal(x) {
case Some(num) => JsonNumber(num)
case None =>
if (Float64.isInfinite(x)) {
if (x > 0.0f64) {
JsonString("Infinity")
} else {
JsonString("-Infinity")
}
} else if (Float64.isNan(x)) {
JsonString("NaN")
} else {
bug!("invalid Float64: ${x}")
}
}
}
}

instance FromJson[Float64] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, Float64] = match x {
case JsonNumber(y) => BigDecimal.tryToFloat64(y) |> Option.toOk(JsonError(p, Set#{"floating-point number", "\"-Infinity\"", "\"Infinity\"", "\"NaN\""}))
Expand All @@ -114,130 +51,62 @@ mod Json {
}
}

instance ToJson[BigDecimal] {
pub def toJson(x: BigDecimal): JsonElement = JsonNumber(x)
}

instance FromJson[BigDecimal] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, BigDecimal] = match x {
case JsonNumber(y) => Ok(y)
case _ => Err(JsonError(p, Set#{"floating-point number"}))
}
}

instance Jsonable[BigDecimal]

instance ToJson[Int8] {
pub def toJson(x: Int8): JsonElement = {
JsonNumber(Int8.toBigDecimal(x))
}
}

instance FromJson[Int8] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, Int8] = match x {
case JsonNumber(y) => BigDecimal.tryToInt8(y) |> Option.toOk(JsonError(p, Set#{"8-bit integer"}))
case _ => Err(JsonError(p, Set#{"8-bit integer"}))
}
}

instance Jsonable[Int8]

instance ToJson[Int16] {
pub def toJson(x: Int16): JsonElement = {
JsonNumber(Int16.toBigDecimal(x))
}
}

instance FromJson[Int16] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, Int16] = match x {
case JsonNumber(y) => BigDecimal.tryToInt16(y) |> Option.toOk(JsonError(p, Set#{"16-bit integer"}))
case _ => Err(JsonError(p, Set#{"16-bit integer"}))
}
}

instance Jsonable[Int16]

instance ToJson[Int32] {
pub def toJson(x: Int32): JsonElement = {
JsonNumber(Int32.toBigDecimal(x))
}
}

instance FromJson[Int32] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, Int32] = match x {
case JsonNumber(y) => BigDecimal.tryToInt32(y) |> Option.toOk(JsonError(p, Set#{"32-bit integer"}))
case _ => Err(JsonError(p, Set#{"32-bit integer"}))
}
}

instance Jsonable[Int32]

instance ToJson[Int64] {
pub def toJson(x: Int64): JsonElement = {
JsonNumber(Int64.toBigDecimal(x))
}
}

instance FromJson[Int64] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, Int64] = match x {
case JsonNumber(y) => BigDecimal.tryToInt64(y) |> Option.toOk(JsonError(p, Set#{"64-bit integer"}))
case _ => Err(JsonError(p, Set#{"64-bit integer"}))
}
}

instance Jsonable[Int64]

instance ToJson[BigInt] {
pub def toJson(x: BigInt): JsonElement = {
JsonNumber(BigInt.toBigDecimal(x))
}
}

instance FromJson[BigInt] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, BigInt] = match x {
case JsonNumber(y) => Ok(BigDecimal.toBigInt(y))
case _ => Err(JsonError(p, Set#{"integer"}))
}
}

instance Jsonable[BigInt]

instance ToJson[String] {
pub def toJson(x: String): JsonElement = JsonString(x)
}

instance FromJson[String] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, String] = match x {
case JsonString(y) => Ok(y)
case _ => Err(JsonError(p, Set#{"string"}))
}
}

instance Jsonable[String]

instance ToJson[List[a]] with ToJson[a] {
pub def toJson(x: List[a]): JsonElement = {
let elems = List.map(Json.ToJson.toJson, x) |> List.toVector;
JsonArray(elems)
}
}

instance FromJson[List[a]] with FromJson[a] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, List[a]] = match x {
case JsonArray(v) => v |> Vector.toList |> List.zipWithIndex |> Result.traverse(match (i, val) -> Json.FromJson.fromJsonAt(p !! i, val))
case _ => Err(JsonError(p, Set#{"array"}))
}
}

instance Jsonable[List[a]] with Jsonable[a]

instance ToJson[Vector[a]] with ToJson[a] {
pub def toJson(x: Vector[a]): JsonElement = {
let elems = Vector.map(Json.ToJson.toJson, x);
JsonArray(elems)
}
}

instance FromJson[Vector[a]] with FromJson[a] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, Vector[a]] = match x {
case JsonArray(v) =>
Expand All @@ -246,18 +115,6 @@ mod Json {
}
}

instance Jsonable[Vector[a]] with Jsonable[a]

instance ToJson[Map[k, v]] with ToString[k], ToJson[v] {
pub def toJson(x: Map[k, v]): JsonElement = {
let map = x
|> Map.toList
|> List.map(match (k, v) -> (ToString.toString(k), Json.ToJson.toJson(v)))
|> List.toMap;
JsonObject(map)
}
}

instance FromJson[Map[k, v]] with FromString[k], Order[k], FromJson[v] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, Map[k, v]] = match x {
case JsonObject(m0) =>
Expand All @@ -278,15 +135,6 @@ mod Json {
}
}

instance Jsonable[Map[k, v]] with ToString[k], FromString[k], Order[k], ToJson[v], FromJson[v]

instance ToJson[Option[a]] with ToJson[a] {
pub def toJson(x: Option[a]): JsonElement = match x {
case Some(y) => JsonArray(Vector#{Json.ToJson.toJson(y)})
case None => JsonArray(Vector#{})
}
}

instance FromJson[Option[a]] with FromJson[a] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, Option[a]] = match x {
case JsonArray(v) if Vector.length(v) == 0 => Ok(None)
Expand All @@ -300,17 +148,6 @@ mod Json {
}
}

instance Jsonable[Option[a]] with FromJson[a], ToJson[a]

instance ToJson[(a, b)] with ToJson[a], ToJson[b] {
pub def toJson(x: (a, b)): JsonElement = {
let (a, b) = x;
let jsonA = Json.ToJson.toJson(a);
let jsonB = Json.ToJson.toJson(b);
JsonArray(Vector#{jsonA, jsonB})
}
}

instance FromJson[(a, b)] with FromJson[a], FromJson[b] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, (a, b)] = match x {
case JsonArray(v) if Vector.length(v) == 2 =>
Expand All @@ -325,18 +162,6 @@ mod Json {
}
}

instance Jsonable[(a, b)] with Jsonable[a], Jsonable[b]

instance ToJson[(a, b, c)] with ToJson[a], ToJson[b], ToJson[c] {
pub def toJson(x: (a, b, c)): JsonElement = {
let (a, b, c) = x;
let jsonA = Json.ToJson.toJson(a);
let jsonB = Json.ToJson.toJson(b);
let jsonC = Json.ToJson.toJson(c);
JsonArray(Vector#{jsonA, jsonB, jsonC})
}
}

instance FromJson[(a, b, c)] with FromJson[a], FromJson[b], FromJson[c] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, (a, b, c)] = match x {
case JsonArray(v) if Vector.length(v) == 3 =>
Expand All @@ -352,19 +177,6 @@ mod Json {
}
}

instance Jsonable[(a, b, c)] with Jsonable[a], Jsonable[b], Jsonable[c]

instance ToJson[(a, b, c, d)] with ToJson[a], ToJson[b], ToJson[c], ToJson[d] {
pub def toJson(x: (a, b, c, d)): JsonElement = {
let (a, b, c, d) = x;
let jsonA = Json.ToJson.toJson(a);
let jsonB = Json.ToJson.toJson(b);
let jsonC = Json.ToJson.toJson(c);
let jsonD = Json.ToJson.toJson(d);
JsonArray(Vector#{jsonA, jsonB, jsonC, jsonD})
}
}

instance FromJson[(a, b, c, d)] with FromJson[a], FromJson[b], FromJson[c], FromJson[d] {
pub def fromJsonAt(p: Path, x: JsonElement): Result[JsonError, (a, b, c, d)] = match x {
case JsonArray(v) if Vector.length(v) == 4 =>
Expand All @@ -381,18 +193,10 @@ mod Json {
}
}

instance Jsonable[(a, b, c, d)] with Jsonable[a], Jsonable[b], Jsonable[c], Jsonable[d]

instance ToJson[JsonElement] {
pub def toJson(x: JsonElement): JsonElement = x
}

instance FromJson[JsonElement] {
pub def fromJsonAt(_: Path, x: JsonElement): Result[JsonError, JsonElement] = Ok(x)
}

instance Jsonable[JsonElement]

///
/// Returns the value associated with the given key in the given map.
///
Expand Down
Loading
Loading