use std::fmt;
use std::fmt::Write as _;
use std::sync::Arc;
use tabnas::Value as Engine;
pub enum Value {
Undefined,
Null,
Bool(bool),
Num(f64),
Str(String),
List(Vec<Value>),
Node(Node),
}
impl Value {
pub fn as_str(&self) -> Option<&str> {
match self {
Value::Str(s) => Some(s),
_ => None,
}
}
pub fn as_node(&self) -> Option<&Node> {
match self {
Value::Node(n) => Some(n),
_ => None,
}
}
pub fn as_list(&self) -> Option<&[Value]> {
match self {
Value::List(l) => Some(l),
_ => None,
}
}
pub fn to_json(&self) -> String {
let mut out = String::new();
write_json(self, &mut out);
out
}
}
impl From<&str> for Value {
fn from(s: &str) -> Self {
Value::Str(s.to_string())
}
}
impl From<String> for Value {
fn from(s: String) -> Self {
Value::Str(s)
}
}
impl From<Node> for Value {
fn from(n: Node) -> Self {
Value::Node(n)
}
}
#[derive(Default)]
pub struct Node {
entries: Vec<(String, Value)>,
}
impl Node {
pub fn new() -> Self {
Node {
entries: Vec::new(),
}
}
pub fn node_type(&self) -> Option<&str> {
self.get("type").and_then(Value::as_str)
}
pub fn get(&self, key: &str) -> Option<&Value> {
self.entries.iter().find(|(k, _)| k == key).map(|(_, v)| v)
}
pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
self.entries
.iter_mut()
.find(|(k, _)| k == key)
.map(|(_, v)| v)
}
pub fn set(&mut self, key: impl Into<String>, value: impl Into<Value>) {
let key = key.into();
let value = value.into();
match self.get_mut(&key) {
Some(slot) => *slot = value,
None => self.entries.push((key, value)),
}
}
pub fn push_to(&mut self, key: &str, value: Value) {
match self.get_mut(key) {
Some(Value::List(list)) => list.push(value),
Some(slot) => *slot = Value::List(vec![value]),
None => self
.entries
.push((key.to_string(), Value::List(vec![value]))),
}
}
pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
self.entries.iter().map(|(k, v)| (k.as_str(), v))
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn to_json(&self) -> String {
let mut out = String::new();
write_steps(vec![Emit::Node(self)], &mut out, Mode::Json);
out
}
}
impl Drop for Node {
fn drop(&mut self) {
let mut pending: Vec<Value> = self.entries.drain(..).map(|(_, v)| v).collect();
while let Some(value) = pending.pop() {
match value {
Value::List(items) => pending.extend(items),
Value::Node(mut node) => {
pending.extend(node.entries.drain(..).map(|(_, v)| v));
}
_ => {}
}
}
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Mode {
Json,
Debug,
}
enum Emit<'a> {
Value(&'a Value),
Node(&'a Node),
Key(&'a str),
Raw(&'static str),
}
fn write_json(root: &Value, out: &mut String) {
write_steps(vec![Emit::Value(root)], out, Mode::Json)
}
fn write_steps(mut steps: Vec<Emit<'_>>, out: &mut String, mode: Mode) {
while let Some(step) = steps.pop() {
match step {
Emit::Raw(text) => out.push_str(text),
Emit::Key(key) => {
write_json_string(key, out);
out.push(':');
}
Emit::Value(Value::Node(node)) | Emit::Node(node) => {
out.push('{');
steps.push(Emit::Raw("}"));
let entries: Vec<(&str, &Value)> = node
.iter()
.filter(|(_, v)| Mode::Debug == mode || !matches!(v, Value::Undefined))
.collect();
for (i, (key, value)) in entries.iter().enumerate().rev() {
steps.push(Emit::Value(value));
steps.push(Emit::Key(key));
if 0 < i {
steps.push(Emit::Raw(","));
}
}
}
Emit::Value(Value::List(items)) => {
out.push('[');
steps.push(Emit::Raw("]"));
for (i, item) in items.iter().enumerate().rev() {
steps.push(Emit::Value(item));
if 0 < i {
steps.push(Emit::Raw(","));
}
}
}
Emit::Value(Value::Undefined) => out.push_str(match mode {
Mode::Json => "null",
Mode::Debug => "undefined",
}),
Emit::Value(Value::Null) => out.push_str("null"),
Emit::Value(Value::Bool(b)) => out.push_str(if *b { "true" } else { "false" }),
Emit::Value(Value::Num(n)) => write_num(*n, out),
Emit::Value(Value::Str(s)) => write_json_string(s, out),
}
}
}
impl fmt::Debug for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut out = String::new();
write_steps(vec![Emit::Value(self)], &mut out, Mode::Debug);
f.write_str(&out)
}
}
impl fmt::Debug for Node {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut out = String::new();
write_steps(vec![Emit::Node(self)], &mut out, Mode::Debug);
f.write_str(&out)
}
}
enum CloneStep<'a> {
Enter(&'a Value),
CloseNode(&'a Node),
CloseList(usize),
}
fn clone_value(root: &Value) -> Value {
let mut steps = vec![CloneStep::Enter(root)];
let mut done: Vec<Value> = Vec::new();
while let Some(step) = steps.pop() {
match step {
CloneStep::Enter(Value::Node(node)) => {
steps.push(CloneStep::CloseNode(node));
for (_, value) in node.entries.iter().rev() {
steps.push(CloneStep::Enter(value));
}
}
CloneStep::Enter(Value::List(items)) => {
steps.push(CloneStep::CloseList(items.len()));
for item in items.iter().rev() {
steps.push(CloneStep::Enter(item));
}
}
CloneStep::Enter(leaf) => done.push(match leaf {
Value::Undefined => Value::Undefined,
Value::Null => Value::Null,
Value::Bool(b) => Value::Bool(*b),
Value::Num(n) => Value::Num(*n),
Value::Str(s) => Value::Str(s.clone()),
Value::List(_) | Value::Node(_) => unreachable!(),
}),
CloneStep::CloseNode(node) => {
let values = done.split_off(done.len() - node.entries.len());
let entries = node
.entries
.iter()
.map(|(k, _)| k.clone())
.zip(values)
.collect();
done.push(Value::Node(Node { entries }));
}
CloneStep::CloseList(n) => {
let items = done.split_off(done.len() - n);
done.push(Value::List(items));
}
}
}
done.pop().expect("the clone produced no value")
}
impl Clone for Value {
fn clone(&self) -> Value {
clone_value(self)
}
}
impl Clone for Node {
fn clone(&self) -> Node {
let mut out = Node::new();
for (key, value) in &self.entries {
out.entries.push((key.clone(), clone_value(value)));
}
out
}
}
fn values_eq(a: &Value, b: &Value) -> bool {
let mut pending: Vec<(&Value, &Value)> = vec![(a, b)];
while let Some((a, b)) = pending.pop() {
match (a, b) {
(Value::Undefined, Value::Undefined) | (Value::Null, Value::Null) => {}
(Value::Bool(a), Value::Bool(b)) if a == b => {}
(Value::Num(a), Value::Num(b)) if a == b => {}
(Value::Str(a), Value::Str(b)) if a == b => {}
(Value::List(a), Value::List(b)) if a.len() == b.len() => {
pending.extend(a.iter().zip(b.iter()));
}
(Value::Node(a), Value::Node(b)) if a.entries.len() == b.entries.len() => {
for ((ak, av), (bk, bv)) in a.entries.iter().zip(b.entries.iter()) {
if ak != bk {
return false;
}
pending.push((av, bv));
}
}
_ => return false,
}
}
true
}
impl PartialEq for Value {
fn eq(&self, other: &Value) -> bool {
values_eq(self, other)
}
}
impl PartialEq for Node {
fn eq(&self, other: &Node) -> bool {
self.entries.len() == other.entries.len()
&& self
.entries
.iter()
.zip(other.entries.iter())
.all(|((ak, _), (bk, _))| ak == bk)
&& self
.entries
.iter()
.zip(other.entries.iter())
.all(|((_, av), (_, bv))| values_eq(av, bv))
}
}
fn write_num(n: f64, out: &mut String) {
if n.is_finite() && n == n.trunc() && n.abs() < 1e15 {
let _ = write!(out, "{}", n as i64);
} else if n.is_finite() {
let _ = write!(out, "{}", n);
} else {
out.push_str("null");
}
}
fn write_json_string(s: &str, out: &mut String) {
out.push('"');
for c in s.chars() {
match c {
'"' => out.push_str("\\\""),
'\\' => out.push_str("\\\\"),
'\n' => out.push_str("\\n"),
'\r' => out.push_str("\\r"),
'\t' => out.push_str("\\t"),
'\u{08}' => out.push_str("\\b"),
'\u{0c}' => out.push_str("\\f"),
c if (c as u32) < 0x20 => {
let _ = write!(out, "\\u{:04x}", c as u32);
}
c => out.push(c),
}
}
out.push('"');
}
impl Value {
pub(crate) fn from_engine(value: &Engine) -> Value {
match value {
Engine::Array(items) => Value::List(items.iter().map(Value::from_engine).collect()),
Engine::Object(fields) => {
let mut node = Node::new();
for (key, field) in fields.iter() {
node.set(key.clone(), Value::from_engine(field));
}
Value::Node(node)
}
scalar => Value::from_scalar(scalar),
}
}
fn from_scalar(value: &Engine) -> Value {
match value {
Engine::String(s) => Value::Str(s.clone()),
Engine::Number(n) => Value::Num(*n),
Engine::Bool(b) => Value::Bool(*b),
Engine::Null => Value::Null,
_ => Value::Undefined,
}
}
pub(crate) fn from_arena(value: Engine) -> Value {
match value {
Engine::Array(records) => {
let records = Arc::try_unwrap(records).unwrap_or_else(|shared| (*shared).clone());
let mut built: Vec<Option<Value>> = Vec::with_capacity(records.len());
built.resize_with(records.len(), || None);
for (id, record) in records.into_iter().enumerate().rev() {
let mut node = Node::new();
if let Engine::Object(fields) = record {
for (key, field) in fields.iter() {
let field = match field {
Engine::Array(items) => Value::List(
items
.iter()
.map(|item| match item {
Engine::Number(child) => built
.get_mut(*child as usize)
.and_then(Option::take)
.unwrap_or(Value::Null),
other => Value::from_scalar(other),
})
.collect(),
),
Engine::Object(_) if "position" == key => position(field),
other => Value::from_scalar(other),
};
node.set(key.clone(), field);
}
}
built[id] = Some(Value::Node(node));
}
built
.first_mut()
.and_then(Option::take)
.unwrap_or(Value::Undefined)
}
Engine::Object(fields) => {
let mut node = Node::new();
for (key, field) in fields.iter() {
let field = match field {
Engine::Array(items) => {
Value::List(items.iter().map(Value::from_scalar).collect())
}
other => Value::from_scalar(other),
};
node.set(key.clone(), field);
}
Value::Node(node)
}
other => Value::from_scalar(&other),
}
}
}
fn position(value: &Engine) -> Value {
let mut out = Node::new();
let fields = match value {
Engine::Object(fields) => Some(fields),
_ => None,
};
for key in ["start", "end"] {
match fields.and_then(|fields| fields.get(key)) {
Some(Engine::Object(point)) => {
let mut at = Node::new();
for (name, n) in point.iter() {
at.set(name.clone(), Value::from_scalar(n));
}
out.set(key, Value::Node(at));
}
_ => out.set(key, Value::Undefined),
}
}
Value::Node(out)
}