1use crate::binding::{self, Bound, SignatureXml};
4use crate::container::DS;
5use crate::timestamp::{self, InputError};
6use crate::xml::{Access, AccessError, Name, Snapshot, Xml};
7use structured_asn1::memory::Work;
8
9mod walk;
10pub use walk::{WalkError, WalkResult, walk};
11
12#[derive(Debug)]
14pub enum Error<E, N> {
15 Input(InputError<E, N>),
17 Binding(binding::BindingError<E, N>),
19}
20
21#[derive(Debug, Clone, Copy)]
23pub struct Counter<N, D, G> {
24 snapshot: Snapshot<D, G>,
25 parent: N,
26 value: N,
27 node: N,
28 child: N,
29}
30
31impl<N: Copy, D: Copy, G: Copy> Counter<N, D, G> {
32 #[must_use]
34 pub fn snapshot(&self) -> Snapshot<D, G> {
35 self.snapshot
36 }
37 #[must_use]
39 pub fn parent(&self) -> N {
40 self.parent
41 }
42 #[must_use]
44 pub fn value(&self) -> N {
45 self.value
46 }
47 #[must_use]
49 pub fn node(&self) -> N {
50 self.node
51 }
52 #[must_use]
54 pub fn child(&self) -> N {
55 self.child
56 }
57}
58
59#[derive(Debug, Clone, Copy)]
61pub struct Checked<N, D, G> {
62 original: Counter<N, D, G>,
63 reference: N,
64 ordinal: usize,
65}
66
67impl<N: Copy, D: Copy, G: Copy> Checked<N, D, G> {
68 #[must_use]
70 pub fn original(&self) -> &Counter<N, D, G> {
71 &self.original
72 }
73 #[must_use]
75 pub fn reference(&self) -> N {
76 self.reference
77 }
78 #[must_use]
80 pub fn ordinal(&self) -> usize {
81 self.ordinal
82 }
83}
84
85pub type Original<X> = Counter<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
87pub type CounterResult<T, X> = Result<T, Error<<X as Xml>::Error, <X as Xml>::Id>>;
89pub type Binding<X> = Checked<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
91
92pub fn read<X: Xml, W: Work>(
95 access: &Access<'_, X, W>,
96 bound: &Bound<X::Id, X::Document, X::Generation>,
97 node: X::Id,
98) -> CounterResult<Original<X>, X> {
99 let parent = timestamp::unsigned_parent(access, bound, node).map_err(Error::Input)?;
100 let mut found = false;
101 for child in access.children(parent) {
102 let child = child.map_err(|cause| Error::Input(InputError::Child(cause)))?;
103 if access
104 .equal_id(child, node)
105 .map_err(|cause| Error::Input(InputError::Resource { node: child, cause }))?
106 {
107 found = true;
108 break;
109 }
110 }
111 if !found {
112 return Err(Error::Input(InputError::Foreign { node }));
113 }
114 let parent = bound.containers().signature();
115 let value = timestamp::singleton(access, parent, DS, "SignatureValue").map_err(Error::Input)?;
116 walk::member(access, parent, value, node)
117}
118
119pub fn bind<X: SignatureXml, W: Work>(
128 child_access: &Access<'_, X, W>,
129 original: Original<X>,
130) -> CounterResult<Binding<X>, X> {
131 if child_access.snapshot() != original.snapshot {
132 return Err(Error::Input(InputError::Access(AccessError::Changed {
133 node: original.child,
134 })));
135 }
136 let (reference, ordinal) = binding::covering_reference(
137 child_access,
138 original.child,
139 binding::Purpose::Counter(original.value),
140 )
141 .map_err(Error::Binding)?;
142 Ok(Checked {
143 original,
144 reference,
145 ordinal,
146 })
147}
148
149fn named<X: Xml, W: Work>(
150 access: &Access<'_, X, W>,
151 node: X::Id,
152 namespace: &str,
153 local: &str,
154) -> CounterResult<bool, X> {
155 access
156 .has_name(node, Name { namespace, local })
157 .map_err(|cause| Error::Input(InputError::Access(cause)))
158}