use super::{
BTreeMap, Decoder, HashMap, Packer, Reader, Schema, Seg, Shape, Unpacker, Value, ValueRef,
Writer, is_metadata_key, typed,
};
fn typed_mark() -> char {
yog_ids::sep::TYPED.chars().next().unwrap_or_default()
}
impl Schema for Value {
fn shape() -> Shape {
Shape::Any
}
fn read(v: &ValueRef<'_>, _: &mut Reader) -> Option<Self> {
Some(v.to_value())
}
fn write(&self) -> Value {
self.clone()
}
}
impl Schema for bool {
fn shape() -> Shape {
Shape::Bool
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
v.as_bool().or_else(|| {
cx.expected("true or false", v);
None
})
}
fn write(&self) -> Value {
Value::Bool(*self)
}
fn encode(&self, w: &mut Writer) {
w.bool(*self);
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
d.bool()
}
fn pack(&self, p: &mut Packer) {
p.put_bool(*self);
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
u.get_bool()
}
}
macro_rules! int_schema {
($($t:ty => $to_bits:ident, $of_bits:ident);*) => {$(
impl Schema for $t {
fn shape() -> Shape {
Shape::Int { min: <$t>::MIN as i64, max: (<$t>::MAX as u64).min(i64::MAX as u64) as i64 }
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
let Some(n) = v.as_i64() else {
cx.expected("an integer", v);
return None;
};
<$t>::try_from(n).ok().or_else(|| {
cx.problem(format!("{n} is out of range ({}..={})", <$t>::MIN, <$t>::MAX));
None
})
}
fn write(&self) -> Value {
Value::Int(*self as i64)
}
fn encode(&self, w: &mut Writer) {
w.int(*self as i64);
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
d.int().and_then(|n| <$t>::try_from(n).ok())
}
fn pack(&self, p: &mut Packer) {
p.put_i(*self as i64);
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
u.get_i().and_then(|n| <$t>::try_from(n).ok())
}
fn pack_list(items: &[Self], p: &mut Packer) {
p.put_uints(items.len(), items.iter().map(|&n| $to_bits(n as i128)));
}
fn unpack_list(u: &mut Unpacker<'_>) -> Option<Vec<Self>> {
u.get_uints(|v| <$t>::try_from($of_bits(v)).ok())
}
fn encode_list(items: &[Self], w: &mut Writer) {
w.ints(items.iter().map(|&n| n as i64));
}
fn decode_list(d: &mut Decoder<'_>) -> Option<Vec<Self>> {
let n = d.ints()?;
let mut out = Vec::with_capacity(n);
for _ in 0..n {
out.push(<$t>::try_from(d.packed_int()?).ok()?);
}
Some(out)
}
}
)*};
}
int_schema!(
i8 => signed_bits, signed_of; i16 => signed_bits, signed_of; i32 => signed_bits, signed_of; i64 => signed_bits, signed_of;
u8 => unsigned_bits, unsigned_of; u16 => unsigned_bits, unsigned_of; u32 => unsigned_bits, unsigned_of;
u64 => unsigned_bits, unsigned_of; usize => unsigned_bits, unsigned_of
);
fn signed_bits(n: i128) -> u64 {
crate::binary::zigzag(n as i64)
}
fn signed_of(v: u64) -> i128 {
i128::from(crate::binary::unzigzag(v))
}
fn unsigned_bits(n: i128) -> u64 {
n as u64
}
fn unsigned_of(v: u64) -> i128 {
i128::from(v)
}
macro_rules! float_schema {
($($t:ty => $one:ident, $many:ident, $read_many:ident, $put:ident, $get:ident, $puts:ident, $gets:ident);*) => {$(
impl Schema for $t {
fn shape() -> Shape {
Shape::Float { bits: u8::BITS * std::mem::size_of::<$t>() as u32 }
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
v.as_f64().map(|f| f as $t).or_else(|| {
cx.expected("a number", v);
None
})
}
fn write(&self) -> Value {
Value::Float(*self as f64)
}
fn encode(&self, w: &mut Writer) {
w.$one(*self);
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
d.float().map(|f| f as $t)
}
fn encode_list(items: &[Self], w: &mut Writer) {
w.$many(items);
}
fn decode_list(d: &mut Decoder<'_>) -> Option<Vec<Self>> {
d.$read_many()
}
fn pack(&self, p: &mut Packer) {
p.$put(*self);
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
u.$get()
}
fn pack_list(items: &[Self], p: &mut Packer) {
p.$puts(items);
}
fn unpack_list(u: &mut Unpacker<'_>) -> Option<Vec<Self>> {
u.$gets()
}
}
)*};
}
float_schema!(
f32 => float32, floats32, floats32, put_f32, get_f32, put_f32s, get_f32s;
f64 => float, floats, floats, put_f64, get_f64, put_f64s, get_f64s
);
impl Schema for String {
fn shape() -> Shape {
Shape::Str
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
match v {
ValueRef::Str(s) if !s.starts_with('@') => Some(s.to_string()),
ValueRef::Str(s) => match typed::classify(s) {
Ok(Value::Str(s)) => Some(s),
Ok(other) => {
cx.problem(format!(
"expected plain text, found {} (write `@@` for a literal `@`)",
other.kind_name()
));
None
}
Err(e) => {
cx.problem_of(yog_ids::data_problem::BAD_TYPED, e);
None
}
},
other => {
cx.expected("a string", other);
None
}
}
}
fn write(&self) -> Value {
Value::Str(self.clone())
}
fn encode(&self, w: &mut Writer) {
w.str(self);
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
d.str()
.filter(|s| !s.starts_with(typed_mark()))
.map(str::to_owned)
}
fn pack(&self, p: &mut Packer) {
p.put_str(self);
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
u.get_str().map(str::to_owned)
}
}
impl Schema for std::borrow::Cow<'static, str> {
fn shape() -> Shape {
Shape::Str
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
String::read(v, cx).map(Self::Owned)
}
fn write(&self) -> Value {
Value::Str(self.to_string())
}
fn encode(&self, w: &mut Writer) {
w.str(self);
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
String::decode(d).map(Self::Owned)
}
fn pack(&self, p: &mut Packer) {
p.put_str(self);
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
String::unpack(u).map(Self::Owned)
}
}
impl Schema for std::path::PathBuf {
fn shape() -> Shape {
Shape::Str
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
String::read(v, cx).map(Self::from)
}
fn write(&self) -> Value {
Value::Str(self.to_string_lossy().into_owned())
}
fn encode(&self, w: &mut Writer) {
w.str(&self.to_string_lossy());
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
String::decode(d).map(Self::from)
}
fn pack(&self, p: &mut Packer) {
p.put_str(&self.to_string_lossy());
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
u.get_str().map(Self::from)
}
}
impl Schema for crate::Atom {
fn shape() -> Shape {
Shape::Atom
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
String::read(v, cx).map(|s| crate::Atom::new(&s))
}
fn write(&self) -> Value {
Value::Str(self.as_str().to_owned())
}
fn encode(&self, w: &mut Writer) {
w.str(self.as_str());
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
d.str()
.filter(|s| !s.starts_with(typed_mark()))
.map(crate::Atom::new)
}
fn pack(&self, p: &mut Packer) {
p.put_u(u64::from(self.number()));
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
crate::Atom::from_number(u32::try_from(u.get_u()?).ok()?)
}
}
impl<T: Schema> Schema for Option<T> {
fn shape() -> Shape {
Shape::Optional(T::shape)
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
if v.is_null() {
Some(None)
} else {
T::read(v, cx).map(Some)
}
}
fn write(&self) -> Value {
self.as_ref().map_or(Value::Null, T::write)
}
fn encode(&self, w: &mut Writer) {
match self {
Some(v) => v.encode(w),
None => {
w.null();
}
}
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
if d.null() {
Some(None)
} else {
T::decode(d).map(Some)
}
}
fn pack(&self, p: &mut Packer) {
p.put_bool(self.is_some());
if let Some(v) = self {
v.pack(p);
}
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
if u.get_bool()? {
T::unpack(u).map(Some)
} else {
Some(None)
}
}
fn absent() -> Option<Self> {
Some(None)
}
fn skip(&self) -> bool {
self.is_none()
}
}
impl<T: Schema> Schema for Box<T> {
fn shape() -> Shape {
T::shape()
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
T::read(v, cx).map(Box::new)
}
fn write(&self) -> Value {
(**self).write()
}
fn encode(&self, w: &mut Writer) {
(**self).encode(w);
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
T::decode(d).map(Box::new)
}
fn pack(&self, p: &mut Packer) {
(**self).pack(p);
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
T::unpack(u).map(Box::new)
}
fn absent() -> Option<Self> {
T::absent().map(Box::new)
}
fn skip(&self) -> bool {
(**self).skip()
}
}
impl<T: Schema> Schema for Vec<T> {
fn shape() -> Shape {
Shape::List(T::shape)
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
let ValueRef::List(items) = v else {
cx.expected("a list", v);
return None;
};
let mut out = Vec::with_capacity(items.len());
let mut ok = true;
for (i, item) in items.iter().enumerate() {
match cx.at(Seg::Index(i), |cx| T::read(item, cx)) {
Some(x) => out.push(x),
None => ok = false,
}
}
ok.then_some(out)
}
fn write(&self) -> Value {
Value::List(self.iter().map(T::write).collect())
}
fn encode(&self, w: &mut Writer) {
T::encode_list(self, w);
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
T::decode_list(d)
}
fn pack(&self, p: &mut Packer) {
T::pack_list(self, p);
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
T::unpack_list(u)
}
}
impl<T: Schema + Ord + Clone> Schema for std::collections::BTreeSet<T> {
fn shape() -> Shape {
Shape::List(T::shape)
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
Vec::<T>::read(v, cx).map(Self::from_iter)
}
fn write(&self) -> Value {
Value::List(self.iter().map(T::write).collect())
}
fn encode(&self, w: &mut Writer) {
T::encode_list(&self.iter().cloned().collect::<Vec<_>>(), w);
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
Vec::<T>::decode(d).map(Self::from_iter)
}
}
impl Schema for Box<str> {
fn shape() -> Shape {
Shape::Str
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
String::read(v, cx).map(String::into_boxed_str)
}
fn write(&self) -> Value {
Value::Str(self.to_string())
}
fn encode(&self, w: &mut Writer) {
w.str(self);
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
String::decode(d).map(String::into_boxed_str)
}
fn pack(&self, p: &mut Packer) {
p.put_str(self);
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
u.get_str().map(Into::into)
}
}
impl Schema for yog_sync::Arc<str> {
fn shape() -> Shape {
Shape::Str
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
String::read(v, cx).map(Into::into)
}
fn write(&self) -> Value {
Value::Str(self.to_string())
}
fn encode(&self, w: &mut Writer) {
w.str(self);
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
String::decode(d).map(Into::into)
}
fn pack(&self, p: &mut Packer) {
p.put_str(self);
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
u.get_shared_str()
}
}
impl<T: Schema> Schema for Box<[T]> {
fn shape() -> Shape {
Shape::List(T::shape)
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
Vec::<T>::read(v, cx).map(Vec::into_boxed_slice)
}
fn write(&self) -> Value {
Value::List(self.iter().map(T::write).collect())
}
fn encode(&self, w: &mut Writer) {
T::encode_list(self, w);
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
T::decode_list(d).map(Vec::into_boxed_slice)
}
fn pack(&self, p: &mut Packer) {
T::pack_list(self, p);
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
T::unpack_list(u).map(Vec::into_boxed_slice)
}
}
impl<T: Schema, const N: usize> Schema for [T; N] {
fn shape() -> Shape {
Shape::List(T::shape)
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
let items = Vec::<T>::read(v, cx)?;
let len = items.len();
items.try_into().ok().or_else(|| {
cx.problem(format!("expected {N} items, found {len}"));
None
})
}
fn write(&self) -> Value {
Value::List(self.iter().map(T::write).collect())
}
fn encode(&self, w: &mut Writer) {
T::encode_list(self, w);
}
fn decode(d: &mut Decoder<'_>) -> Option<Self> {
T::decode_list(d)?.try_into().ok()
}
fn pack(&self, p: &mut Packer) {
T::pack_list(self, p);
}
fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
T::unpack_list(u)?.try_into().ok()
}
}
impl Schema for () {
fn shape() -> Shape {
Shape::Any
}
fn read(_v: &ValueRef<'_>, _cx: &mut Reader) -> Option<Self> {
Some(())
}
fn write(&self) -> Value {
Value::Null
}
}
impl<T: Schema, E: Schema> Schema for Result<T, E> {
fn shape() -> Shape {
Shape::Any
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
let ValueRef::Map(m) = v else {
cx.expected("{ ok } or { err }", v);
return None;
};
if let Some(ok) = m.get(RESULT_OK) {
return cx
.at(Seg::Key(RESULT_OK.into()), |cx| T::read(ok, cx))
.map(Ok);
}
let Some(err) = m.get(RESULT_ERR) else {
cx.expected("{ ok } or { err }", v);
return None;
};
cx.at(Seg::Key(RESULT_ERR.into()), |cx| E::read(err, cx))
.map(Err)
}
fn write(&self) -> Value {
let (key, value) = match self {
Ok(t) => (RESULT_OK, t.write()),
Err(e) => (RESULT_ERR, e.write()),
};
Value::Map([(key.to_owned(), value)].into_iter().collect())
}
}
pub(crate) const RESULT_OK: &str = "ok";
pub(crate) const RESULT_ERR: &str = "err";
macro_rules! tuples {
($($what:literal: $n:literal => ($($t:ident $i:tt),+);)+) => {$(
impl<$($t: Schema),+> Schema for ($($t,)+) {
fn shape() -> Shape {
Shape::List(Value::shape)
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
let ValueRef::List(items) = v else {
cx.expected($what, v);
return None;
};
if items.len() != $n {
cx.problem(format!("expected {} items, found {}", $n, items.len()));
return None;
}
let read = ($(cx.at(Seg::Index($i), |cx| $t::read(&items[$i], cx)),)+);
Some(($(read.$i?,)+))
}
fn write(&self) -> Value {
Value::List(vec![$(self.$i.write()),+])
}
}
)+};
}
tuples! {
"a pair [a, b]": 2 => (A 0, B 1);
"a triple [a, b, c]": 3 => (A 0, B 1, C 2);
"four [a, b, c, d]": 4 => (A 0, B 1, C 2, D 3);
}
fn read_map<T: Schema>(
v: &ValueRef,
cx: &mut Reader,
mut put: impl FnMut(String, T),
) -> Option<()> {
let map = cx.map(v)?;
let mut ok = true;
for (k, item) in map.iter() {
if is_metadata_key(k) {
continue;
}
match cx.at(Seg::Key(k.to_string()), |cx| T::read(item, cx)) {
Some(x) => put(k.to_string(), x),
None => ok = false,
}
}
ok.then_some(())
}
impl<T: Schema> Schema for BTreeMap<String, T> {
fn shape() -> Shape {
Shape::Map(T::shape)
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
let mut out = BTreeMap::new();
read_map(v, cx, |k, x| {
out.insert(k, x);
})?;
Some(out)
}
fn write(&self) -> Value {
Value::Map(self.iter().map(|(k, v)| (k.clone(), v.write())).collect())
}
}
impl<T: Schema> Schema for HashMap<String, T> {
fn shape() -> Shape {
Shape::Map(T::shape)
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
let mut out = HashMap::new();
read_map(v, cx, |k, x| {
out.insert(k, x);
})?;
Some(out)
}
fn write(&self) -> Value {
let mut keys: Vec<&String> = self.keys().collect();
keys.sort();
Value::Map(
keys.into_iter()
.map(|k| (k.clone(), self[k].write()))
.collect(),
)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Ordered<T>(pub Vec<(String, T)>);
impl<T> Default for Ordered<T> {
fn default() -> Self {
Self(Vec::new())
}
}
impl<T: Schema> Schema for Ordered<T> {
fn shape() -> Shape {
Shape::Map(T::shape)
}
fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
let mut out = Vec::new();
read_map(v, cx, |k, x| out.push((k, x)))?;
Some(Ordered(out))
}
fn write(&self) -> Value {
Value::Map(self.0.iter().map(|(k, v)| (k.clone(), v.write())).collect())
}
}