willow_data_model/paths/
codec.rs

1use compact_u64::*;
2use ufotofu::{ConsumeAtLeastError, codec_prelude::*};
3
4use super::*;
5
6/// Essentially how to encode a Path, but working with an arbitrary iterator of components. Path encoding consists of calling this directly, relative path encoding consists of first encoding the length of the greatest common suffix and *then* calling this.
7async fn encode_from_iterator_of_components<'a, const MCL: usize, C, I>(
8    consumer: &mut C,
9    path_length: u64,
10    component_count: u64,
11    components: I,
12) -> Result<(), C::Error>
13where
14    C: BulkConsumer<Item = u8> + ?Sized,
15    I: Iterator<Item = &'a Component<MCL>>,
16{
17    // First byte contains two 4-bit tags of `CompactU64`s:
18    // total path length in bytes: 4 bit tag at offset zero
19    // total number of components: 4 bit tag at offset four
20    let mut header = 0;
21    write_tag(&mut header, 4, 0, path_length);
22    write_tag(&mut header, 4, 4, component_count);
23    consumer.consume_item(header).await?;
24
25    // Next, encode the total path length in compact bytes.
26    cu64_encode(path_length, 4, consumer).await?;
27
28    // Next, encode the  total number of components in compact bytes.
29    cu64_encode(component_count, 4, consumer).await?;
30
31    // Then, encode the components. Each is prefixed by its length as an 8-bit-tag CompactU64, except for the final component.
32    for (i, component) in components.enumerate() {
33        // The length of the final component is omitted (because a decoder can infer it from the total length and all prior components' lengths).
34        if i as u64 + 1 != component_count {
35            cu64_encode_standalone(component.len() as u64, consumer).await?;
36        }
37
38        // Each component length (if any) is followed by the raw component data itself.
39        consumer
40            .bulk_consume_full_slice(component.as_ref())
41            .await
42            .map_err(ConsumeAtLeastError::into_reason)?;
43    }
44
45    Ok(())
46}
47
48/// Implements [encode_path](https://willowprotocol.org/specs/encodings/index.html#encode_path).
49impl<const MCL: usize, const MCC: usize, const MPL: usize> Encodable for Path<MCL, MCC, MPL> {
50    async fn encode<C>(&self, consumer: &mut C) -> Result<(), C::Error>
51    where
52        C: BulkConsumer<Item = u8> + ?Sized,
53    {
54        encode_from_iterator_of_components::<MCL, _, _>(
55            consumer,
56            self.total_length() as u64,
57            self.component_count() as u64,
58            self.components(),
59        )
60        .await
61    }
62}
63
64// Decodes the path length and component count as expected at the start of a path encoding, generic over whether the encoding must be canonic or not.
65// Implemented as a dedicated function so that it can be used in both absolute and relative decoding.
66async fn decode_total_length_and_component_count_maybe_canonic<const CANONIC: bool, P>(
67    producer: &mut P,
68) -> Result<(usize, usize), DecodeError<P::Final, P::Error, Blame>>
69where
70    P: BulkProducer<Item = u8> + ?Sized,
71{
72    // Decode the first byte - the two compact width tags for the path length and component count.
73    let header = producer.produce_item().await?;
74
75    // Next, decode the total path length and the component count.
76    let total_length = if CANONIC {
77        cu64_decode_canonic(header, 4, 0, producer)
78            .await
79            .map_err(|err| err.map_other(|_| Blame::TheirFault))?
80    } else {
81        cu64_decode(header, 4, 0, producer)
82            .await
83            .map_err(|err| err.map_other(|_| Blame::TheirFault))?
84    };
85
86    let component_count = if CANONIC {
87        cu64_decode_canonic(header, 4, 4, producer)
88            .await
89            .map_err(|err| err.map_other(|_| Blame::TheirFault))?
90    } else {
91        cu64_decode(header, 4, 4, producer)
92            .await
93            .map_err(|err| err.map_other(|_| Blame::TheirFault))?
94    };
95
96    // Convert them from u64 to usize, error if usize cannot represent the number.
97    let total_length = Blame::u64_to_usize(total_length)?;
98    let component_count = Blame::u64_to_usize(component_count)?;
99
100    Ok((total_length, component_count))
101}
102
103// Decodes the components of a path encoding, generic over whether the encoding must be canonic or not. Appends them into a PathBuilder. Needs to know the total length of components that had already been appended to that PathBuilder before.
104// Implemented as a dedicated function so that it can be used in both absolute and relative decoding.
105async fn decode_components_maybe_canonic<
106    const CANONIC: bool,
107    const MCL: usize,
108    const MCC: usize,
109    const MPL: usize,
110    P,
111>(
112    producer: &mut P,
113    mut builder: PathBuilder<MCL, MCC, MPL>,
114    initial_accumulated_component_length: usize,
115    remaining_component_count: usize,
116    expected_total_length: usize,
117) -> Result<Path<MCL, MCC, MPL>, DecodeError<P::Final, P::Error, Blame>>
118where
119    P: BulkProducer<Item = u8> + ?Sized,
120{
121    // Decode the actual components.
122    // We track the sum of the lengths of all decoded components so far, because we need it to determine the length of the final component.
123    let mut accumulated_component_length = initial_accumulated_component_length;
124
125    // Handle decoding of the empty path with dedicated logic to prevent underflows in loop counters =S
126    if remaining_component_count == 0 {
127        if expected_total_length > accumulated_component_length {
128            // Claimed length is incorrect
129            Err(DecodeError::Other(Blame::TheirFault))
130        } else {
131            // Nothing more to do, decoding an empty path turns out to be simple!
132            Ok(builder.build())
133        }
134    } else {
135        // We have at least one component.
136
137        // Decode all but the final one (because the final one is encoded without its lenght and hence requires dedicated logic to decode).
138        for _ in 1..remaining_component_count {
139            let component_len = Blame::u64_to_usize(if CANONIC {
140                cu64_decode_canonic_standalone(producer)
141                    .await
142                    .map_err(|err| err.map_other(|_| Blame::TheirFault))?
143            } else {
144                cu64_decode_standalone(producer)
145                    .await
146                    .map_err(|err| err.map_other(|_| Blame::TheirFault))?
147            })?;
148
149            if component_len > MCL {
150                // Decoded path must respect the MCL.
151                return Err(DecodeError::Other(Blame::TheirFault));
152            } else {
153                // Increase the accumulated length, accounting for errors.
154                accumulated_component_length = accumulated_component_length
155                    .checked_add(component_len)
156                    .ok_or(DecodeError::Other(Blame::TheirFault))?;
157
158                // Copy the component bytes into the Path.
159                builder
160                    .append_component_from_bulk_producer(component_len, producer)
161                    .await?;
162            }
163        }
164
165        // For the final component, compute its length. If the computation result would be negative, then the encoding was invalid.
166        let final_component_length = expected_total_length
167            .checked_sub(accumulated_component_length)
168            .ok_or(DecodeError::Other(Blame::TheirFault))?;
169
170        if final_component_length > MCL {
171            // Decoded path must respect the MCL.
172            Err(DecodeError::Other(Blame::TheirFault))
173        } else {
174            // Copy the final component bytes into the Path.
175            builder
176                .append_component_from_bulk_producer(final_component_length, producer)
177                .await?;
178
179            // What a journey. We are done!
180            Ok(builder.build())
181        }
182    }
183}
184
185// Decodes a path, generic over whether the encoding must be canonic or not.
186async fn decode_maybe_canonic<
187    const CANONIC: bool,
188    const MCL: usize,
189    const MCC: usize,
190    const MPL: usize,
191    P,
192>(
193    producer: &mut P,
194) -> Result<Path<MCL, MCC, MPL>, DecodeError<P::Final, P::Error, Blame>>
195where
196    P: BulkProducer<Item = u8> + ?Sized,
197{
198    let (total_length, component_count) =
199        decode_total_length_and_component_count_maybe_canonic::<CANONIC, _>(producer).await?;
200
201    // Preallocate all storage for the path. Error if the total length or component_count are greater than MPL and MCC respectively allow.
202    let builder = PathBuilder::new(total_length, component_count)
203        .map_err(|_| DecodeError::Other(Blame::TheirFault))?;
204
205    decode_components_maybe_canonic::<CANONIC, MCL, MCC, MPL, _>(
206        producer,
207        builder,
208        0,
209        component_count,
210        total_length,
211    )
212    .await
213}
214
215/// Implements [EncodePath](https://willowprotocol.org/specs/encodings/index.html#EncodePath).
216impl<const MCL: usize, const MCC: usize, const MPL: usize> Decodable for Path<MCL, MCC, MPL> {
217    type ErrorReason = Blame;
218
219    async fn decode<P>(
220        producer: &mut P,
221    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorReason>>
222    where
223        P: BulkProducer<Item = u8> + ?Sized,
224    {
225        decode_maybe_canonic::<false, MCL, MCC, MPL, _>(producer).await
226    }
227}
228
229/// Implements [encode_path](https://willowprotocol.org/specs/encodings/index.html#encode_path).
230impl<const MCL: usize, const MCC: usize, const MPL: usize> DecodableCanonic
231    for Path<MCL, MCC, MPL>
232{
233    type ErrorCanonic = Blame;
234
235    async fn decode_canonic<P>(
236        producer: &mut P,
237    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorCanonic>>
238    where
239        P: BulkProducer<Item = u8> + ?Sized,
240    {
241        decode_maybe_canonic::<true, MCL, MCC, MPL, _>(producer).await
242    }
243}
244
245// Separate function to allow for reuse in relative encoding.
246fn encoding_len_from_iterator_of_components<'a, const MCL: usize, I>(
247    path_length: u64,
248    component_count: usize,
249    components: I,
250) -> usize
251where
252    I: Iterator<Item = &'a Component<MCL>>,
253{
254    let mut total_enc_len = 1; // First byte for the two four-bit tags at the start of the encoding.
255
256    total_enc_len += cu64_len_of_encoding(4, path_length);
257    total_enc_len += cu64_len_of_encoding(4, component_count as u64);
258
259    for (i, comp) in components.enumerate() {
260        if i + 1 < component_count {
261            total_enc_len += cu64_len_of_encoding(8, comp.len() as u64) + 1;
262        }
263
264        total_enc_len += comp.len();
265    }
266
267    total_enc_len
268}
269
270/// Implements [encode_path](https://willowprotocol.org/specs/encodings/index.html#encode_path).
271impl<const MCL: usize, const MCC: usize, const MPL: usize> EncodableKnownLength
272    for Path<MCL, MCC, MPL>
273{
274    fn len_of_encoding(&self) -> usize {
275        encoding_len_from_iterator_of_components::<MCL, _>(
276            self.total_length() as u64,
277            self.component_count(),
278            self.components(),
279        )
280    }
281}
282
283////////////////////////////////////
284// Relative encoding path <> path //
285////////////////////////////////////
286
287/// Implements [path_rel_path](https://willowprotocol.org/specs/encodings/index.html#path_rel_path).
288impl<const MCL: usize, const MCC: usize, const MPL: usize> RelativeEncodable<Path<MCL, MCC, MPL>>
289    for Path<MCL, MCC, MPL>
290{
291    async fn relative_encode<Consumer>(
292        &self,
293        rel: &Path<MCL, MCC, MPL>,
294        consumer: &mut Consumer,
295    ) -> Result<(), Consumer::Error>
296    where
297        Consumer: BulkConsumer<Item = u8> + ?Sized,
298    {
299        let lcp = self.longest_common_prefix(rel);
300
301        cu64_encode_standalone(lcp.component_count() as u64, consumer).await?;
302
303        let suffix_length = self.total_length() - lcp.total_length();
304        let suffix_component_count = self.component_count() - lcp.component_count();
305
306        encode_from_iterator_of_components::<MCL, _, _>(
307            consumer,
308            suffix_length as u64,
309            suffix_component_count as u64,
310            self.suffix_components(lcp.component_count()),
311        )
312        .await
313    }
314
315    /// Any path can be encoded relative to every path.
316    fn can_be_encoded_relative_to(&self, _rel: &Path<MCL, MCC, MPL>) -> bool {
317        true
318    }
319}
320
321// Decodes a path relative to another path, generic over whether the encoding must be canonic or not.
322async fn relative_decode_maybe_canonic<
323    const CANONIC: bool,
324    const MCL: usize,
325    const MCC: usize,
326    const MPL: usize,
327    P,
328>(
329    producer: &mut P,
330    rel: &Path<MCL, MCC, MPL>,
331) -> Result<Path<MCL, MCC, MPL>, DecodeError<P::Final, P::Error, Blame>>
332where
333    P: BulkProducer<Item = u8> + ?Sized,
334{
335    let prefix_component_count = Blame::u64_to_usize(if CANONIC {
336        cu64_decode_canonic_standalone(producer)
337            .await
338            .map_err(|err| err.map_other(|_| Blame::TheirFault))?
339    } else {
340        cu64_decode_standalone(producer)
341            .await
342            .map_err(|err| err.map_other(|_| Blame::TheirFault))?
343    })?;
344
345    let (suffix_length, suffix_component_count) =
346        decode_total_length_and_component_count_maybe_canonic::<CANONIC, _>(producer).await?;
347
348    if prefix_component_count > rel.component_count() {
349        return Err(DecodeError::Other(Blame::TheirFault));
350    }
351
352    let prefix_path_length = rel.total_length_of_prefix(prefix_component_count);
353
354    let total_length = prefix_path_length
355        .checked_add(suffix_length)
356        .ok_or(DecodeError::Other(Blame::TheirFault))?;
357    let total_component_count = prefix_component_count
358        .checked_add(suffix_component_count)
359        .ok_or(DecodeError::Other(Blame::TheirFault))?;
360
361    // Preallocate all storage for the path. Error if the total length or component_count are greater than MPL and MCC respectively allow.
362    let builder = PathBuilder::new_from_prefix(
363        total_length,
364        total_component_count,
365        rel,
366        prefix_component_count,
367    )
368    .map_err(|_| DecodeError::Other(Blame::TheirFault))?;
369
370    // Decode the remaining components, add them to the builder, then build.
371    let decoded = decode_components_maybe_canonic::<CANONIC, MCL, MCC, MPL, _>(
372        producer,
373        builder,
374        prefix_path_length,
375        suffix_component_count,
376        total_length,
377    )
378    .await?;
379
380    if CANONIC {
381        // Did the encoding use the *longest* common prefix?
382        if prefix_component_count == rel.component_count() {
383            // Could not have taken a longer prefix of `r`, i.e., the prefix was maximal.
384            Ok(decoded)
385        } else if prefix_component_count == decoded.component_count() {
386            // The prefix was the full path to decode, so it clearly was chosen maximally.
387            Ok(decoded)
388        } else {
389            // We check whether the next-longer prefix of `r` could have also been used for encoding. If so, error.
390            // To efficiently check, we check whether the next component of `r` is equal to its counterpart in what we decoded.
391            // Both next components exist, otherwise we would have been in an earlier branch of the `if` expression.
392            if rel.component(prefix_component_count).unwrap()
393                == decoded.component(prefix_component_count).unwrap()
394            {
395                // Could have used a longer prefix for decoding. Not canonic!
396                Err(DecodeError::Other(Blame::TheirFault))
397            } else {
398                // Encoding was minimal, yay =)
399                Ok(decoded)
400            }
401        }
402    } else {
403        // No additional canonicity checks needed.
404        Ok(decoded)
405    }
406}
407
408/// Implements [EncodePathRelativePath](https://willowprotocol.org/specs/encodings/index.html#EncodePathRelativePath).
409impl<const MCL: usize, const MCC: usize, const MPL: usize> RelativeDecodable<Path<MCL, MCC, MPL>>
410    for Path<MCL, MCC, MPL>
411{
412    type ErrorReason = Blame;
413
414    async fn relative_decode<P>(
415        rel: &Path<MCL, MCC, MPL>,
416        producer: &mut P,
417    ) -> Result<Self, DecodeError<P::Final, P::Error, Blame>>
418    where
419        P: BulkProducer<Item = u8> + ?Sized,
420    {
421        relative_decode_maybe_canonic::<false, MCL, MCC, MPL, _>(producer, rel).await
422    }
423}
424
425/// Implements [path_relative_path](https://willowprotocol.org/specs/encodings/index.html#path_rel_path).
426impl<const MCL: usize, const MCC: usize, const MPL: usize>
427    RelativeDecodableCanonic<Path<MCL, MCC, MPL>> for Path<MCL, MCC, MPL>
428{
429    type ErrorCanonic = Blame;
430
431    async fn relative_decode_canonic<P>(
432        rel: &Path<MCL, MCC, MPL>,
433        producer: &mut P,
434    ) -> Result<Self, DecodeError<P::Final, P::Error, Blame>>
435    where
436        P: BulkProducer<Item = u8> + ?Sized,
437    {
438        relative_decode_maybe_canonic::<true, MCL, MCC, MPL, _>(producer, rel).await
439    }
440}
441
442/// /// Implements [path_rel_path](https://willowprotocol.org/specs/encodings/index.html#path_rel_path).
443impl<const MCL: usize, const MCC: usize, const MPL: usize>
444    RelativeEncodableKnownLength<Path<MCL, MCC, MPL>> for Path<MCL, MCC, MPL>
445{
446    fn len_of_relative_encoding(&self, rel: &Path<MCL, MCC, MPL>) -> usize {
447        let lcp = self.longest_common_prefix(rel);
448        let path_len_of_suffix = self.total_length() - lcp.total_length();
449        let component_count_of_suffix = self.component_count() - lcp.component_count();
450
451        let mut total_enc_len = 0;
452
453        // Number of components in the longest common prefix, encoded as a CompactU64 with an 8-bit tag.
454        total_enc_len += cu64_len_of_encoding(8, lcp.component_count() as u64) + 1;
455
456        total_enc_len += encoding_len_from_iterator_of_components::<MCL, _>(
457            path_len_of_suffix as u64,
458            component_count_of_suffix,
459            self.suffix_components(lcp.component_count()),
460        );
461
462        total_enc_len
463    }
464}
465
466////////////////////////////////
467// path extends path encoding //
468////////////////////////////////
469
470/// Implementations of the [EncodePathExtendsPath](https://willowprotocol.org/specs/encodings/index.html#EncodePathExtendsPath) encoding relation.
471pub mod path_extends_path {
472    use super::*;
473
474    #[cfg(feature = "dev")]
475    use arbitrary::Arbitrary;
476
477    /// Implements encoding for the [path_extends_path](https://willowprotocol.org/specs/encodings/index.html#path_extends_path) encoding function.
478    pub async fn encode_path_extends_path<const MCL: usize, const MCC: usize, const MPL: usize, C>(
479        path: &Path<MCL, MCC, MPL>,
480        prefix: &Path<MCL, MCC, MPL>,
481        consumer: &mut C,
482    ) -> Result<(), C::Error>
483    where
484        C: BulkConsumer<Item = u8> + ?Sized,
485    {
486        if !path.is_prefixed_by(prefix) {
487            panic!("Tried to encode relative to a non-prefix with PathExtendsPath");
488        }
489
490        let extends_count = prefix.component_count();
491
492        let path_len = path.total_length() - prefix.total_length();
493        let diff = path.component_count() - extends_count;
494
495        encode_from_iterator_of_components(
496            consumer,
497            path_len as u64,
498            diff as u64,
499            path.suffix_components(extends_count),
500        )
501        .await?;
502
503        Ok(())
504    }
505
506    /// Returns the length of the encoding of `path` relative to `prefix` according to the [path_extends_path](https://willowprotocol.org/specs/encodings/index.html#path_extends_path) encoding function.
507    pub fn path_extends_path_encoding_len<const MCL: usize, const MCC: usize, const MPL: usize>(
508        path: &Path<MCL, MCC, MPL>,
509        prefix: &Path<MCL, MCC, MPL>,
510    ) -> usize {
511        let prefix_count = prefix.component_count();
512
513        let path_len = path.total_length() - prefix.total_length();
514        let diff = path.component_count() - prefix_count;
515
516        encoding_len_from_iterator_of_components(
517            path_len as u64,
518            diff,
519            path.suffix_components(prefix_count),
520        )
521    }
522
523    /// Implements decoding for the [EncodePathExtendsPath](https://willowprotocol.org/specs/encodings/index.html#EncodePathExtendsPath) encoding relation.
524    pub async fn decode_path_extends_path<const MCL: usize, const MCC: usize, const MPL: usize, P>(
525        prefix: &Path<MCL, MCC, MPL>,
526        producer: &mut P,
527    ) -> Result<Path<MCL, MCC, MPL>, DecodeError<P::Final, P::Error, Blame>>
528    where
529        P: BulkProducer<Item = u8> + ?Sized,
530    {
531        let suffix = Path::<MCL, MCC, MPL>::decode(producer)
532            .await
533            .map_err(|err| err.map_other(From::from))?;
534
535        let prefix_count = prefix.component_count();
536
537        let total_length = prefix.total_length() + suffix.total_length();
538        let total_count = prefix_count + suffix.component_count();
539
540        let mut path_builder =
541            PathBuilder::new_from_prefix(total_length, total_count, prefix, prefix_count)
542                .map_err(|_err| DecodeError::Other(Blame::TheirFault))?;
543
544        for component in suffix.components() {
545            path_builder.append_component(component);
546        }
547
548        Ok(path_builder.build())
549    }
550
551    /// Implements canonic decoding for the [path_extends_path](https://willowprotocol.org/specs/encodings/index.html#path_extends_path) encoding function.
552    pub async fn decode_path_extends_path_canonic<
553        const MCL: usize,
554        const MCC: usize,
555        const MPL: usize,
556        P,
557    >(
558        prefix: &Path<MCL, MCC, MPL>,
559        producer: &mut P,
560    ) -> Result<Path<MCL, MCC, MPL>, DecodeError<P::Final, P::Error, Blame>>
561    where
562        P: BulkProducer<Item = u8> + ?Sized,
563    {
564        let suffix = Path::<MCL, MCC, MPL>::decode_canonic(producer)
565            .await
566            .map_err(|err| err.map_other(From::from))?;
567
568        let prefix_count = prefix.component_count();
569
570        let total_length = prefix.total_length() + suffix.total_length();
571        let total_count = prefix_count + suffix.component_count();
572
573        let mut path_builder =
574            PathBuilder::new_from_prefix(total_length, total_count, prefix, prefix_count)
575                .map_err(|_err| DecodeError::Other(Blame::TheirFault))?;
576
577        for component in suffix.components() {
578            path_builder.append_component(component);
579        }
580
581        Ok(path_builder.build())
582    }
583
584    /// A wrapper type around [`Path`] whose implementations of the [codec_relative] traits implement the [EncodePathExtendsPath](https://willowprotocol.org/specs/encodings/index.html#encsec_EncodePathExtendsPath) encoding relation.
585    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, Debug)]
586    #[cfg_attr(feature = "dev", derive(Arbitrary))]
587    pub struct CodecPathExtendsPath<const MCL: usize, const MCC: usize, const MPL: usize>(
588        pub Path<MCL, MCC, MPL>,
589    );
590
591    /// Implements [path_extends_path](https://willowprotocol.org/specs/encodings/index.html#path_extends_path).
592    impl<const MCL: usize, const MCC: usize, const MPL: usize>
593        RelativeEncodable<Path<MCL, MCC, MPL>> for CodecPathExtendsPath<MCL, MCC, MPL>
594    {
595        async fn relative_encode<C>(
596            &self,
597            rel: &Path<MCL, MCC, MPL>,
598            consumer: &mut C,
599        ) -> Result<(), C::Error>
600        where
601            C: BulkConsumer<Item = u8> + ?Sized,
602        {
603            encode_path_extends_path(&self.0, rel, consumer).await
604        }
605
606        /// Returns `true` iff `rel` is a prefix of `self`.
607        fn can_be_encoded_relative_to(&self, rel: &Path<MCL, MCC, MPL>) -> bool {
608            rel.is_prefix_of(&self.0)
609        }
610    }
611
612    /// Implements [path_extends_path](https://willowprotocol.org/specs/encodings/index.html#path_extends_path).
613    impl<const MCL: usize, const MCC: usize, const MPL: usize>
614        RelativeEncodableKnownLength<Path<MCL, MCC, MPL>> for CodecPathExtendsPath<MCL, MCC, MPL>
615    {
616        fn len_of_relative_encoding(&self, rel: &Path<MCL, MCC, MPL>) -> usize {
617            path_extends_path_encoding_len(&self.0, rel)
618        }
619    }
620
621    /// Implements [EncodePathExtendsPath](https://willowprotocol.org/specs/encodings/index.html#EncodePathExtendsPath).
622    impl<const MCL: usize, const MCC: usize, const MPL: usize>
623        RelativeDecodable<Path<MCL, MCC, MPL>> for CodecPathExtendsPath<MCL, MCC, MPL>
624    {
625        type ErrorReason = Blame;
626
627        async fn relative_decode<P>(
628            rel: &Path<MCL, MCC, MPL>,
629            producer: &mut P,
630        ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorReason>>
631        where
632            P: BulkProducer<Item = u8> + ?Sized,
633            Self: Sized,
634        {
635            Ok(Self(decode_path_extends_path(rel, producer).await?))
636        }
637    }
638
639    /// Implements [path_extends_path](https://willowprotocol.org/specs/encodings/index.html#path_extends_path).
640    impl<const MCL: usize, const MCC: usize, const MPL: usize>
641        RelativeDecodableCanonic<Path<MCL, MCC, MPL>> for CodecPathExtendsPath<MCL, MCC, MPL>
642    {
643        type ErrorCanonic = Blame;
644
645        async fn relative_decode_canonic<P>(
646            rel: &Path<MCL, MCC, MPL>,
647            producer: &mut P,
648        ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorReason>>
649        where
650            P: BulkProducer<Item = u8> + ?Sized,
651            Self: Sized,
652        {
653            Ok(Self(decode_path_extends_path_canonic(rel, producer).await?))
654        }
655    }
656}