1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use crate::func::context::*;

use super::*;

/// ```rust
/// # use radn::rcore::Context;
/// # use radn::rcore::Factory;
/// # use radn::rcore::FactoryExt;
/// # use radn::rcore::Mentionable;
/// # use radn::rstd::ResolverExt;
/// # use radn::rstd::SerializableExt;
/// # use radn::rstd::singular::SingularResolver;
/// # fn test<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>>(a: &A) {
/// let resolver = SingularResolver::from_mentionable(a).into_rc();
/// let bytes = a.bytes();
/// let factory = a.factory();
/// factory.parse_slice(&bytes, &resolver);
/// # }
/// ```
pub struct SingularResolver<'a, Ctx: Context<'a>> {
    topology: Arc<dyn Topology<'a, Ctx>>,
}

impl<'a, Ctx: Context<'a>> SingularResolver<'a, Ctx> {
    pub fn from_mentionable<A: Mentionable<'a, Ctx>>(a: &A) -> Self {
        Self {
            topology: a.topology(),
        }
    }

    fn try_resolve(
        self: Arc<Self>,
        address: Address,
    ) -> Result<HashResolution<'a, Ctx>, SingularError> {
        let point = self
            .topology
            .point_at(address.index)
            .ok_or(SingularError::OutOfBounds {
                index: address.index,
                len: self.topology.points_count(),
            })?;
        if point.s_hash() != address.point {
            Err(SingularError::Mismatch {
                index: address.index,
                expected: address.point,
                point: point.s_hash(),
            })
        } else {
            Ok(point.clone().singular())
        }
    }
}

impl<'a, Ctx: Context<'a>> Resolver<'a, Ctx> for SingularResolver<'a, Ctx> {
    fn resolve(self: Arc<Self>, address: Address) -> HashResolution<'a, Ctx> {
        self.try_resolve(address)
            .map_err(SingularError::into)
            .map_err(Err)
            .unwrap_or_else(Ctx::pure)
    }
}