automerge/rust/automerge/src/autoserde.rs
Alex Good dd3c6d1303
Move rust workspace into ./rust
After some discussion with PVH I realise that the repo structure in the
last reorg was very rust-centric. In an attempt to put each language on
a level footing move the rust code and project files into ./rust
2022-10-16 19:55:51 +01:00

109 lines
3 KiB
Rust

use serde::ser::{SerializeMap, SerializeSeq};
use crate::{Automerge, ObjId, ObjType, Value};
/// A wrapper type which implements [`serde::Serialize`] for an [`Automerge`].
#[derive(Debug)]
pub struct AutoSerde<'a>(&'a Automerge);
impl<'a> From<&'a Automerge> for AutoSerde<'a> {
fn from(a: &'a Automerge) -> Self {
AutoSerde(a)
}
}
impl<'a> serde::Serialize for AutoSerde<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
AutoSerdeMap {
doc: self.0,
obj: ObjId::Root,
}
.serialize(serializer)
}
}
struct AutoSerdeMap<'a> {
doc: &'a Automerge,
obj: ObjId,
}
impl<'a> serde::Serialize for AutoSerdeMap<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut map_ser = serializer.serialize_map(Some(self.doc.length(&ObjId::Root)))?;
for key in self.doc.keys(&self.obj) {
// SAFETY: This only errors if the object ID is unknown, but we construct this type
// with a known real object ID
let (val, obj) = self.doc.get(&self.obj, &key).unwrap().unwrap();
let serdeval = AutoSerdeVal {
doc: self.doc,
val,
obj,
};
map_ser.serialize_entry(&key, &serdeval)?;
}
map_ser.end()
}
}
struct AutoSerdeSeq<'a> {
doc: &'a Automerge,
obj: ObjId,
}
impl<'a> serde::Serialize for AutoSerdeSeq<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut seq_ser = serializer.serialize_seq(None)?;
for i in 0..self.doc.length(&self.obj) {
// SAFETY: This only errors if the object ID is unknown, but we construct this type
// with a known real object ID
let (val, obj) = self.doc.get(&self.obj, i).unwrap().unwrap();
let serdeval = AutoSerdeVal {
doc: self.doc,
val,
obj,
};
seq_ser.serialize_element(&serdeval)?;
}
seq_ser.end()
}
}
struct AutoSerdeVal<'a> {
doc: &'a Automerge,
val: Value<'a>,
obj: ObjId,
}
impl<'a> serde::Serialize for AutoSerdeVal<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match &self.val {
Value::Object(ObjType::Map | ObjType::Table) => {
let map = AutoSerdeMap {
doc: self.doc,
obj: self.obj.clone(),
};
map.serialize(serializer)
}
Value::Object(ObjType::List | ObjType::Text) => {
let seq = AutoSerdeSeq {
doc: self.doc,
obj: self.obj.clone(),
};
seq.serialize(serializer)
}
Value::Scalar(v) => v.serialize(serializer),
}
}
}