121 lines
3.5 KiB
Rust
121 lines
3.5 KiB
Rust
use super::{
|
|
dectx::{DeCtx, DeCtxT},
|
|
*,
|
|
};
|
|
|
|
/// Preferred way to parse [Point]s off of a [Serializer].
|
|
pub(super) struct Addresses {
|
|
current: usize,
|
|
}
|
|
|
|
impl Addresses {
|
|
/// Read the next [Address].
|
|
pub fn next<'a>(
|
|
&mut self,
|
|
deserializer: &'a mut dyn Deserializer,
|
|
) -> Result<Address, &'a [u8]> {
|
|
let point = deserializer.read_n_const::<HASH_SIZE>()?;
|
|
let address = Address {
|
|
point,
|
|
index: self.current,
|
|
};
|
|
self.current += 1;
|
|
Ok(address)
|
|
}
|
|
|
|
/// Start reading the [Address]es.
|
|
fn start() -> Self {
|
|
Addresses { current: 0 }
|
|
}
|
|
}
|
|
|
|
pub(super) trait InliningAddresses<E>: Stream {
|
|
fn inext_address(
|
|
self,
|
|
addresses: &mut Addresses,
|
|
err: impl FnOnce(&[u8]) -> E,
|
|
) -> Result<(Address, Self), E> {
|
|
let (point, deserializer) = self.iread_n_const::<HASH_SIZE>(err)?;
|
|
let address = Address {
|
|
point,
|
|
index: addresses.current,
|
|
};
|
|
addresses.current += 1;
|
|
Ok((address, deserializer))
|
|
}
|
|
}
|
|
|
|
impl<E, D: ?Sized + Stream> InliningAddresses<E> for D {}
|
|
|
|
fn parse_slice<'a, Ctx: Context<'a>, F: FactoryParse<'a, Ctx>>(
|
|
factory: &F,
|
|
slice: &[u8],
|
|
resolver: &Arc<dyn Resolver<'a, Ctx>>,
|
|
) -> ParseResult<'a, F> {
|
|
let mut deserializer = SliceDeserializer::from(slice);
|
|
let mentionable = factory.deserialize(&mut DeCtxT {
|
|
deserializer: &mut deserializer,
|
|
resolver,
|
|
addresses: &mut Addresses::start(),
|
|
} as &mut dyn DeCtx<'a, Ctx>)?;
|
|
let tail = deserializer.read_all();
|
|
if tail.is_empty() {
|
|
Ok(mentionable)
|
|
} else {
|
|
factory.extend(mentionable, tail)
|
|
}
|
|
}
|
|
|
|
impl<'a, Ctx: Context<'a>, F: FactoryParse<'a, Ctx>> FactoryExt<'a, Ctx> for F {
|
|
fn parse_slice(
|
|
&self,
|
|
slice: &[u8],
|
|
resolver: &Arc<dyn Resolver<'a, Ctx>>,
|
|
) -> ParseResult<'a, Self> {
|
|
parse_slice::<Ctx, _>(self, slice, resolver)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn can_read_one_address() {
|
|
let mut addresses = Addresses::start();
|
|
let point = b"A".repeat(HASH_SIZE);
|
|
let mut deserializer = SliceDeserializer::from(point.as_slice());
|
|
let address = addresses.next(&mut deserializer).unwrap();
|
|
assert_eq!(address.point, point.as_slice());
|
|
assert_eq!(address.index, 0);
|
|
}
|
|
|
|
#[test]
|
|
fn can_read_three_addresses_and_fail_on_extra_tail() {
|
|
let mut addresses = Addresses::start();
|
|
let point0 = b"A".repeat(HASH_SIZE);
|
|
let point1 = b"B".repeat(HASH_SIZE);
|
|
let point2 = b"C".repeat(HASH_SIZE);
|
|
let tail = b"tail";
|
|
let mut source = Vec::new();
|
|
source.extend(&point0);
|
|
source.extend(&point1);
|
|
source.extend(&point2);
|
|
source.extend(tail);
|
|
let mut deserializer = SliceDeserializer::from(source.as_slice());
|
|
let address = addresses.next(&mut deserializer).unwrap();
|
|
assert_eq!(address.point, point0.as_slice());
|
|
assert_eq!(address.index, 0);
|
|
let address = addresses.next(&mut deserializer).unwrap();
|
|
assert_eq!(address.point, point1.as_slice());
|
|
assert_eq!(address.index, 1);
|
|
let address = addresses.next(&mut deserializer).unwrap();
|
|
assert_eq!(address.point, point2.as_slice());
|
|
assert_eq!(address.index, 2);
|
|
if tail.len() < HASH_SIZE {
|
|
let err = addresses.next(&mut deserializer).unwrap_err();
|
|
assert_eq!(err, tail);
|
|
}
|
|
}
|
|
}
|