use super::kinds::{Logical, Physical};
use super::{Encrypt, MapSink, SeqSink, Sink};
pub struct Tee<A, B>(pub A, pub B);
impl<A: Sink, B: Sink<Error = A::Error>> Sink for Tee<A, B> {
type Ok = (A::Ok, B::Ok);
type Error = A::Error;
type Seq = Tee<A::Seq, B::Seq>;
type Map = Tee<A::Map, B::Map>;
fn scalar(self, ty: Option<Logical>, value: Physical<'_>) -> Result<Self::Ok, A::Error> {
let (a, b) = (self.0, self.1);
a.scalar(ty, value)
.and_then(|a| b.scalar(ty, value).map(|b| (a, b)))
}
fn seq(self, len: Option<usize>) -> Result<Self::Seq, A::Error> {
let (a, b) = (self.0, self.1);
a.seq(len).and_then(|a| b.seq(len).map(|b| Tee(a, b)))
}
fn map(self, len: Option<usize>) -> Result<Self::Map, A::Error> {
let (a, b) = (self.0, self.1);
a.map(len).and_then(|a| b.map(len).map(|b| Tee(a, b)))
}
fn passthrough<P: Encrypt + Clone>(self, value: P) -> Result<Self::Ok, A::Error> {
let (a, b) = (self.0, self.1);
a.passthrough(value.clone())
.and_then(|a| b.passthrough(value).map(|b| (a, b)))
}
}
impl<A: SeqSink, B: SeqSink<Error = A::Error>> SeqSink for Tee<A, B> {
type Ok = (A::Ok, B::Ok);
type Error = A::Error;
type Element<'s>
= Tee<A::Element<'s>, B::Element<'s>>
where
Self: 's;
fn element(&mut self) -> Result<Self::Element<'_>, A::Error> {
let Tee(a, b) = self;
a.element().and_then(|a| b.element().map(|b| Tee(a, b)))
}
fn end(self) -> Result<Self::Ok, A::Error> {
let (a, b) = (self.0, self.1);
a.end().and_then(|a| b.end().map(|b| (a, b)))
}
}
impl<A: MapSink, B: MapSink<Error = A::Error>> MapSink for Tee<A, B> {
type Ok = (A::Ok, B::Ok);
type Error = A::Error;
type Entry<'s>
= Tee<A::Entry<'s>, B::Entry<'s>>
where
Self: 's;
fn entry(&mut self, key: &str) -> Result<Self::Entry<'_>, A::Error> {
let Tee(a, b) = self;
a.entry(key).and_then(|a| b.entry(key).map(|b| Tee(a, b)))
}
fn end(self) -> Result<Self::Ok, A::Error> {
let (a, b) = (self.0, self.1);
a.end().and_then(|a| b.end().map(|b| (a, b)))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::plaintext::record::{record, Record};
use std::collections::BTreeMap;
#[test]
fn both_sides_see_the_same_walk() {
let mut value = BTreeMap::new();
value.insert("xs", vec![Some(1u32), None]);
value.insert("name", vec![]);
let mut left = Vec::new();
let mut right = Vec::new();
value
.clone()
.visit(Tee(Record(&mut left), Record(&mut right)))
.expect("ok");
assert_eq!(left, right);
assert_eq!(left, record(value).expect("ok"));
}
#[test]
fn a_tee_of_tees_still_shares_one_walk() {
let (mut a, mut b, mut c) = (Vec::new(), Vec::new(), Vec::new());
vec![vec![1i64, 2], vec![3]]
.visit(Tee(Tee(Record(&mut a), Record(&mut b)), Record(&mut c)))
.expect("ok");
assert_eq!(a, b);
assert_eq!(b, c);
assert_eq!(a.len(), 14);
}
#[test]
fn both_sides_see_a_byte_leaf_as_one_scalar() {
use crate::plaintext::record::{Event, Owned};
let (mut left, mut right) = (Vec::new(), Vec::new());
vec![1u8, 2]
.visit(Tee(Record(&mut left), Record(&mut right)))
.expect("ok");
assert_eq!(left, right);
assert_eq!(left, [Event::Scalar(None, Owned::Bytes(vec![1, 2]))]);
}
#[test]
fn an_unknown_logical_type_reaches_both_sides_unchanged() {
use crate::plaintext::kinds::{Logical, Physical};
use crate::plaintext::record::{Event, Owned};
use crate::plaintext::Raw;
let ty = Logical::from_wire(200, 9).expect("unknown");
let (mut left, mut right) = (Vec::new(), Vec::new());
Raw(Some(ty), Physical::Text("x"))
.visit(Tee(Record(&mut left), Record(&mut right)))
.expect("ok");
assert_eq!(left, right);
assert_eq!(left, [Event::Scalar(Some(ty), Owned::Text("x".into()))]);
assert!(matches!(left[0], Event::Scalar(Some(t), _) if t.to_wire() == (200, 9)));
}
#[test]
fn visit_map_walks_each_entry_into_its_own_sink() {
use crate::plaintext::record::{Event, Owned};
use crate::plaintext::visit_map;
let mut log = Vec::new();
visit_map(Record(&mut log), Some(2), [("a", 1u16), ("b", 2u16)]).expect("ok");
let int = |v| Event::Scalar(None, Owned::Int(crate::plaintext::Int::U16(v)));
assert_eq!(
log,
[
Event::Map(Some(2)),
Event::Entry("a".into()),
int(1),
Event::Entry("b".into()),
int(2),
Event::EndMap,
]
);
}
#[test]
fn passthrough_reaches_both_sides() {
use crate::plaintext::record::{Event, Owned};
let (mut left, mut right) = (Vec::new(), Vec::new());
Tee(Record(&mut left), Record(&mut right))
.passthrough(vec![1u16, 2])
.expect("ok");
assert_eq!(left, right);
assert_eq!(
left,
[
Event::Passthrough,
Event::Seq(Some(2)),
Event::Element,
Event::Scalar(None, Owned::Int(crate::plaintext::Int::U16(1))),
Event::Element,
Event::Scalar(None, Owned::Int(crate::plaintext::Int::U16(2))),
Event::EndSeq,
]
);
}
#[test]
fn a_tee_stops_at_the_first_side_that_fails() {
use crate::plaintext::record::{Event, RecordError};
struct Refuse;
impl Sink for Refuse {
type Ok = ();
type Error = RecordError;
type Seq = Self;
type Map = Self;
fn scalar(self, _: Option<Logical>, _: Physical<'_>) -> Result<(), RecordError> {
Err(RecordError("refused".into()))
}
fn seq(self, _: Option<usize>) -> Result<Self, RecordError> {
Ok(self)
}
fn map(self, _: Option<usize>) -> Result<Self, RecordError> {
Ok(self)
}
fn passthrough<P: Encrypt + Clone>(self, _: P) -> Result<(), RecordError> {
Ok(())
}
}
impl SeqSink for Refuse {
type Ok = ();
type Error = RecordError;
type Element<'s> = Refuse;
fn element(&mut self) -> Result<Refuse, RecordError> {
Ok(Refuse)
}
fn end(self) -> Result<(), RecordError> {
Ok(())
}
}
impl MapSink for Refuse {
type Ok = ();
type Error = RecordError;
type Entry<'s> = Refuse;
fn entry(&mut self, _: &str) -> Result<Refuse, RecordError> {
Ok(Refuse)
}
fn end(self) -> Result<(), RecordError> {
Ok(())
}
}
let mut right = Vec::new();
let err = vec![1u32, 2]
.visit(Tee(Refuse, Record(&mut right)))
.expect_err("refused");
assert_eq!(err.0, "refused");
assert_eq!(right, [Event::Seq(Some(2)), Event::Element]);
let mut left = Vec::new();
let err = vec![1u32, 2]
.visit(Tee(Record(&mut left), Refuse))
.expect_err("refused");
assert_eq!(err.0, "refused");
assert_eq!(left.len(), 3, "{left:?}");
}
}