use crate::{ItemKind, TaggedItem};
#[allow(unused_variables)]
pub trait Visitor<'a, Err> {
fn visit_simple(&mut self, item: TaggedItem<'a>) -> Result<(), Err> {
Ok(())
}
fn visit_array_begin(&mut self, array: TaggedItem<'a>, size: Option<u64>) -> Result<bool, Err> {
Ok(true)
}
fn visit_array_index(&mut self, array: TaggedItem<'a>, index: u64) -> Result<bool, Err> {
Ok(true)
}
fn visit_array_end(&mut self, array: TaggedItem<'a>) -> Result<(), Err> {
Ok(())
}
fn visit_dict_begin(&mut self, dict: TaggedItem<'a>, size: Option<u64>) -> Result<bool, Err> {
Ok(true)
}
fn visit_dict_key(
&mut self,
dict: TaggedItem<'a>,
key: TaggedItem<'a>,
is_first: bool,
) -> Result<bool, Err> {
Ok(true)
}
fn visit_dict_end(&mut self, dict: TaggedItem<'a>) -> Result<(), Err> {
Ok(())
}
}
pub fn visit<'a, 'b, Err, V: Visitor<'b, Err>>(v: &'a mut V, c: TaggedItem<'b>) -> Result<(), Err> {
match c.kind() {
ItemKind::Array(iter) => {
if v.visit_array_begin(c, iter.size())? {
for (idx, item) in iter.enumerate() {
if v.visit_array_index(c, idx as u64)? {
visit(v, item.tagged_item())?;
}
}
}
v.visit_array_end(c)
}
ItemKind::Dict(iter) => {
if v.visit_dict_begin(c, iter.size())? {
let mut is_first = true;
for (key, item) in iter {
if v.visit_dict_key(c, key.tagged_item(), is_first)? {
visit(v, item.tagged_item())?;
}
is_first = false;
}
}
v.visit_dict_end(c)
}
_ => v.visit_simple(c),
}
}
#[cfg(test)]
mod tests {
use crate::{constants::TAG_CBOR_ITEM, CborBuilder, ItemKind, PathElement, TaggedItem, Writer};
use pretty_assertions::assert_eq;
#[test]
fn smoke() {
let x = CborBuilder::new().write_array([1, 2], |b| {
b.write_bool(true, [3, 4]);
b.write_dict([5, 6], |b| {
b.with_key("k", |b| b.write_pos(5, [7, 8]));
b.with_cbor_key(|b| b.write_neg(42, [9, 10]), |b| b.write_null([11, 12]));
});
b.write_bytes(
CborBuilder::new()
.write_array([], |b| {
b.write_bool(false, [0]);
b.write_undefined([42]);
})
.as_slice(),
[TAG_CBOR_ITEM],
);
});
struct Visitor<'b>(&'b mut Vec<String>, bool);
impl<'a, 'b> super::Visitor<'a, &'static str> for Visitor<'b> {
fn visit_simple(&mut self, item: TaggedItem<'a>) -> Result<(), &'static str> {
self.0.push(format!("simple {:?}", item));
if self.1 {
Err("buh")
} else {
Ok(())
}
}
fn visit_array_begin(
&mut self,
array: TaggedItem<'a>,
size: Option<u64>,
) -> Result<bool, &'static str> {
self.0.push(format!("array_begin {:?} {:?}", array, size));
Ok(true)
}
fn visit_array_index(
&mut self,
array: TaggedItem<'a>,
index: u64,
) -> Result<bool, &'static str> {
self.0.push(format!("array_index {:?} {}", array, index));
Ok(true)
}
fn visit_array_end(&mut self, array: TaggedItem<'a>) -> Result<(), &'static str> {
self.0.push(format!("array_end {:?}", array));
Ok(())
}
fn visit_dict_begin(
&mut self,
dict: TaggedItem<'a>,
size: Option<u64>,
) -> Result<bool, &'static str> {
self.0.push(format!("dict_begin {:?} {:?}", dict, size));
Ok(true)
}
fn visit_dict_key(
&mut self,
dict: TaggedItem<'a>,
key: TaggedItem<'a>,
is_first: bool,
) -> Result<bool, &'static str> {
self.0
.push(format!("dict_key {:?} {:?} {}", dict, key, is_first));
Ok(true)
}
fn visit_dict_end(&mut self, dict: TaggedItem<'a>) -> Result<(), &'static str> {
self.0.push(format!("dict_end {:?}", dict));
Ok(())
}
}
let mut trace = Vec::new();
x.visit(&mut Visitor(trace.as_mut(), false)).unwrap();
assert_eq!(
trace,
vec![
"array_begin TaggedItem(Tags(1,2), Array(Some(3))) Some(3)",
"array_index TaggedItem(Tags(1,2), Array(Some(3))) 0",
"simple TaggedItem(Tags(3,4), Bool(true))",
"array_index TaggedItem(Tags(1,2), Array(Some(3))) 1",
"dict_begin TaggedItem(Tags(5,6), Dict(Some(2))) Some(2)",
"dict_key TaggedItem(Tags(5,6), Dict(Some(2))) TaggedItem(Tags(), Str(k)) true",
"simple TaggedItem(Tags(7,8), Pos(5))",
"dict_key TaggedItem(Tags(5,6), Dict(Some(2))) TaggedItem(Tags(9,10), Neg(42)) false",
"simple TaggedItem(Tags(11,12), Null)",
"dict_end TaggedItem(Tags(5,6), Dict(Some(2)))",
"array_index TaggedItem(Tags(1,2), Array(Some(3))) 2",
"simple TaggedItem(Tags(24), Bytes(82c0f4d82af7))",
"array_end TaggedItem(Tags(1,2), Array(Some(3)))",
]
);
trace.clear();
assert_eq!(
x.visit(&mut Visitor(trace.as_mut(), true)).unwrap_err(),
"buh"
);
assert_eq!(
trace,
vec![
"array_begin TaggedItem(Tags(1,2), Array(Some(3))) Some(3)",
"array_index TaggedItem(Tags(1,2), Array(Some(3))) 0",
"simple TaggedItem(Tags(3,4), Bool(true))",
]
);
trace.clear();
x.index([PathElement::Number(2)])
.unwrap()
.visit(&mut Visitor(trace.as_mut(), false))
.unwrap();
assert_eq!(
trace,
vec![
"array_begin TaggedItem(Tags(), Array(Some(2))) Some(2)",
"array_index TaggedItem(Tags(), Array(Some(2))) 0",
"simple TaggedItem(Tags(0), Bool(false))",
"array_index TaggedItem(Tags(), Array(Some(2))) 1",
"simple TaggedItem(Tags(42), Undefined)",
"array_end TaggedItem(Tags(), Array(Some(2)))",
]
);
assert_eq!(
x.index([PathElement::Number(2), PathElement::Number(1)])
.unwrap()
.kind(),
ItemKind::Undefined
);
}
}