1use crate::paths::{Path, path_extends_path};
4#[cfg(feature = "dev")]
5use arbitrary::Arbitrary;
6use compact_u64::{cu64_decode_standalone, cu64_encode_standalone};
7use derive_more::{Display, Error};
8use ufotofu::{
9 codec::{Blame, DecodeError},
10 codec_prelude::RelativeDecodable,
11 codec_relative::RelativeEncodable,
12};
13
14#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
15pub struct PrivatePathContext<const MCL: usize, const MCC: usize, const MPL: usize> {
17 private: Path<MCL, MCC, MPL>,
19 rel: Path<MCL, MCC, MPL>,
21}
22
23#[derive(Debug, Display, Error, Clone, Copy)]
25#[display("private and relative paths are not related")]
26pub struct ComponentsNotRelatedError;
27
28impl<const MCL: usize, const MCC: usize, const MPL: usize> PrivatePathContext<MCL, MCC, MPL> {
29 pub fn new(
33 private: Path<MCL, MCC, MPL>,
34 rel: Path<MCL, MCC, MPL>,
35 ) -> Result<Self, ComponentsNotRelatedError> {
36 if !private.is_related_to(&rel) {
37 return Err(ComponentsNotRelatedError {});
38 }
39
40 Ok(Self { private, rel })
41 }
42
43 pub unsafe fn new_unchecked(private: Path<MCL, MCC, MPL>, rel: Path<MCL, MCC, MPL>) -> Self {
49 Self { private, rel }
50 }
51
52 pub fn private(&self) -> &Path<MCL, MCC, MPL> {
54 &self.private
55 }
56
57 pub fn rel(&self) -> &Path<MCL, MCC, MPL> {
59 &self.rel
60 }
61}
62
63#[cfg(feature = "dev")]
64impl<'a, const MCL: usize, const MCC: usize, const MPL: usize> Arbitrary<'a>
65 for PrivatePathContext<MCL, MCC, MPL>
66{
67 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
68 let private: Path<MCL, MCC, MPL> = Arbitrary::arbitrary(u)?;
69 let rel: Path<MCL, MCC, MPL> = Arbitrary::arbitrary(u)?;
70
71 if !private.is_related_to(&rel) {
72 return Err(arbitrary::Error::IncorrectFormat);
73 }
74
75 Ok(Self { private, rel })
76 }
77}
78
79impl<const MCL: usize, const MCC: usize, const MPL: usize>
80 RelativeEncodable<PrivatePathContext<MCL, MCC, MPL>> for Path<MCL, MCC, MPL>
81{
82 async fn relative_encode<C>(
83 &self,
84 rel: &PrivatePathContext<MCL, MCC, MPL>,
85 consumer: &mut C,
86 ) -> Result<(), C::Error>
87 where
88 C: ufotofu::BulkConsumer<Item = u8> + ?Sized,
89 {
90 let rel_count = rel.rel.component_count();
91 let private_count = rel.private.component_count();
92
93 if private_count <= rel_count {
94 path_extends_path::encode_path_extends_path(self, &rel.rel, consumer).await?;
95 } else {
96 let lcp = self.longest_common_prefix(&rel.private);
97
98 let lcp_len = lcp.component_count();
99 cu64_encode_standalone(lcp_len as u64, consumer).await?;
100
101 if lcp_len >= private_count {
102 path_extends_path::encode_path_extends_path(self, rel.private(), consumer).await?;
103 }
104 }
105
106 Ok(())
107 }
108
109 fn can_be_encoded_relative_to(&self, rel: &PrivatePathContext<MCL, MCC, MPL>) -> bool {
111 if !rel.rel().is_prefix_of(self) {
112 return false;
113 }
114
115 if !self.is_related_to(rel.private()) {
116 return false;
117 }
118
119 true
120 }
121}
122
123impl<const MCL: usize, const MCC: usize, const MPL: usize>
124 RelativeDecodable<PrivatePathContext<MCL, MCC, MPL>> for Path<MCL, MCC, MPL>
125{
126 type ErrorReason = Blame;
127
128 async fn relative_decode<P>(
129 rel: &PrivatePathContext<MCL, MCC, MPL>,
130 producer: &mut P,
131 ) -> Result<Self, ufotofu::codec::DecodeError<P::Final, P::Error, Self::ErrorReason>>
132 where
133 P: ufotofu::BulkProducer<Item = u8> + ?Sized,
134 Self: Sized,
135 {
136 let rel_count = rel.rel.component_count();
137 let private_count = rel.private.component_count();
138
139 if private_count <= rel_count {
140 path_extends_path::decode_path_extends_path(rel.rel(), producer).await
141 } else {
142 let private_component_count = cu64_decode_standalone(producer)
143 .await
144 .map_err(|err| err.map_other(|_| Blame::TheirFault))?;
145
146 if private_component_count < rel.rel().component_count() as u64 {
148 return Err(DecodeError::Other(Blame::TheirFault));
149 }
150
151 if private_component_count >= private_count as u64 {
152 path_extends_path::decode_path_extends_path(rel.private(), producer).await
153 } else {
154 let decoded = rel
155 .private
156 .create_prefix(private_component_count as usize)
157 .ok_or(DecodeError::Other(Blame::TheirFault))?;
158
159 Ok(decoded)
160 }
161 }
162 }
163}