use crate::core::*; use crate::std::*; struct CastResolver<'a, Ctx: 'a + Context> { points: Vec>>, } #[derive(Debug)] pub enum CastError<'a> { Typeless(TypelessError<'a>), AddressIndexOutOfBounds { index: usize, length: usize, }, AddressPointMismatch { expected: Hash, received: Hash, index: usize, }, } impl<'a> Display for CastError<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { CastError::Typeless(typeless_error) => { f.write_fmt(format_args!("typeless cast error: {}", typeless_error)) } CastError::AddressIndexOutOfBounds { index, length } => f.write_fmt(format_args!( "cast index out of bound: {}>={}", index, length )), CastError::AddressPointMismatch { expected, received, index, } => f.write_fmt(format_args!( "address mismatch at index {}: {}>={}", index, hex::encode(expected), hex::encode(received), )), } } } impl<'a, Ctx: 'a + Context> Resolver<'a, Ctx> for CastResolver<'a, Ctx> where Ctx::LookupError<'a>: From>, { fn resolve(self: Rc, address: Address) -> HashResolution<'a, Ctx> { let point = match self.points.get(address.index) { Some(point) => point, None => { return Ctx::T::pure(Err(CastError::AddressIndexOutOfBounds { index: address.index, length: self.points.len(), } .into())); } }; if point.point != address.point { return Ctx::T::pure(Err(CastError::AddressPointMismatch { expected: point.point, received: address.point, index: address.index, } .into())); } Ctx::T::fmap( |resolved| match resolved { Ok(mentionable) => { let resolver: Rc> = Rc::new(CastResolver { points: mentionable.points(), }); Ok((mentionable.bytes(), resolver)) } Err(error) => Err(match error { ResolutionError::Lookup(lookup_error) => lookup_error, ResolutionError::Parse(parse_error) => CastError::Typeless(parse_error).into(), }), }, point.resolve(), ) } } pub type CastResult<'a, Ctx, A> = Result>::Fctr as Factory<'a, Ctx>>::ParseError>; impl<'a, Ctx: Context> TypelessMentionable<'a, Ctx> where Ctx::LookupError<'a>: From>, { pub fn cast>(&self, factory: A::Fctr) -> CastResult<'a, Ctx, A> { factory.parse_slice( &self.bytes(), Rc::new(CastResolver { points: self.points(), }), ) } }