#![allow(dead_code)]
use serpent_serializer::value::{Key, Table, Value};
use std::sync::atomic::{AtomicUsize, Ordering};
#[must_use]
pub fn norm_addr(s: &str) -> String {
let mut out = String::new();
let bytes = s.as_bytes();
let mut i = 0;
while i < bytes.len() {
if s[i..].starts_with("0x") {
out.push_str("0xADDR");
i += 2;
while i < bytes.len() && bytes[i].is_ascii_hexdigit() {
i += 1;
}
} else {
out.push(bytes[i] as char);
i += 1;
}
}
out
}
static FID: AtomicUsize = AtomicUsize::new(1);
#[must_use]
pub fn func(bytecode: Option<Vec<u8>>) -> Value {
Value::Function(serpent_serializer::value::Func {
id: FID.fetch_add(1, Ordering::Relaxed),
bytecode,
})
}
#[must_use]
pub fn s(b: &[u8]) -> Value {
Value::Str(b.to_vec())
}
#[must_use]
pub fn sk(b: &[u8]) -> Key {
Key::Str(b.to_vec())
}
#[must_use]
pub fn nk(n: f64) -> Key {
Key::Number(n)
}
#[must_use]
pub fn table() -> Table {
Table::new()
}
#[must_use]
pub fn deep_eq(a: &Value, b: &Value) -> bool {
let mut seen: Vec<(usize, usize)> = Vec::new();
deep_eq_inner(a, b, &mut seen)
}
fn deep_eq_inner(a: &Value, b: &Value, seen: &mut Vec<(usize, usize)>) -> bool {
match (a, b) {
(Value::Nil, Value::Nil) => true,
(Value::Bool(x), Value::Bool(y)) => x == y,
(Value::Number(x), Value::Number(y)) => x == y || (x.is_nan() && y.is_nan()),
(Value::Str(x), Value::Str(y)) => x == y,
(Value::Table(x), Value::Table(y)) => {
let pair = (x.id(), y.id());
if seen.contains(&pair) {
return true;
}
seen.push(pair);
let xe = x.entries();
let ye = y.entries();
let present = |list: &[(Key, Value)], k: &Key| {
list.iter()
.find(|(kk, _)| kk.same(k))
.map(|(_, v)| v.clone())
};
let count = |list: &[(Key, Value)]| {
list.iter()
.filter(|(_, v)| !matches!(v, Value::Nil))
.count()
};
if count(&xe) != count(&ye) {
return false;
}
for (k, v) in &xe {
if matches!(v, Value::Nil) {
continue;
}
match present(&ye, k) {
Some(v2) => {
if !deep_eq_inner(v, &v2, seen) {
return false;
}
}
None => return false,
}
}
true
}
_ => false,
}
}