///|
struct DraftData {
schema : String
shafts : Int
threading : Array[Int]
lifts : Array[Array[Int]]
} derive(ToJson, FromJson)
///|
/// Versioned JSON interchange. Limit text before parsing; core parser rejects excess nesting.
pub fn read_json(text : String) -> Result[Draft, String] {
if text.length() > 1048576 {
return Err("weave.json_size")
}
try {
let mut depth = 0
let mut quoted = false
let mut escaped = false
for c in text.iter() {
if quoted {
if escaped {
escaped = false
} else if c == '\\' {
escaped = true
} else if c == '"' {
quoted = false
}
} else if c == '"' {
quoted = true
} else if c == '{' || c == '[' {
depth = depth + 1
if depth > 8 {
return Err("weave.json_depth")
}
} else if c == '}' || c == ']' {
depth = depth - 1
}
}
let value = @json.parse(text)
guard value is Object(fields) else { return Err("weave.json_object") }
if fields.length() != 4 ||
!fields.contains("schema") ||
!fields.contains("shafts") ||
!fields.contains("threading") ||
!fields.contains("lifts") {
return Err("weave.json_fields")
}
guard fields.get("shafts") is Some(Number(n, ..)) else {
return Err("weave.json_integer")
}
if n < 1 || n > 64 || n != n.to_int().to_double() {
return Err("weave.json_integer")
}
guard fields.get("threading") is Some(Array(threads)) else {
return Err("weave.json_array")
}
guard fields.get("lifts") is Some(Array(rows)) else {
return Err("weave.json_array")
}
if threads.length() > 2048 ||
rows.length() > 2048 ||
threads.length() * rows.length() > 262144 {
return Err("weave.size")
}
let groups = [threads]
for row in rows {
guard row is Array(ids) else { return Err("weave.json_array") }
if ids.length() > 64 {
return Err("weave.lift")
}
groups.push(ids)
}
for group in groups {
for item in group {
guard item is Number(id, ..) else { return Err("weave.json_integer") }
if id < 1 || id > 64 || id != id.to_int().to_double() {
return Err("weave.json_integer")
}
}
}
let data : DraftData = @json.from_json(value)
if data.schema != "moonweave/1" {
return Err("weave.json_version")
}
draft(data.shafts, data.threading, data.lifts)
} catch {
_ => Err("weave.json_syntax_or_type")
}
}
///|
pub fn Draft::write_json(self : Draft) -> String {
let data : DraftData = {
schema: "moonweave/1",
shafts: self.shafts,
threading: self.threads(),
lifts: self.liftplan(),
}
data.to_json().stringify()
}