Skip to content

Commit 0472c2f

Browse files
committed
Wrappers for TLV records of a variable-length type
TLV records containing a single variable-length type should not encoded the types length in the value since it is redundant. Add a wrapper type that can be used within a TLV stream to support the correct behavior during serialization and de-serialization. Likewise, subtypes of such records must include type lengths. Add a wrapper type that includes the length using a specified unsigned type.
1 parent 11c6f06 commit 0472c2f

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

lightning/src/util/ser.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,67 @@ impl_array!(PUBLIC_KEY_SIZE); // for PublicKey
516516
impl_array!(64); // for ecdsa::Signature and schnorr::Signature
517517
impl_array!(1300); // for OnionPacket.hop_data
518518

519+
/// For variable-length values within TLV subtypes where the length cannot be inferred from the
520+
/// enclosing TLV record.
521+
///
522+
/// The length is encoded as an unsigned `U` type.
523+
#[derive(Clone)]
524+
pub(crate) struct WithLength<T, U>(pub T, pub core::marker::PhantomData<U>);
525+
526+
impl<T: Writeable> Writeable for WithLength<Vec<T>, u8> {
527+
#[inline]
528+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
529+
(self.0.len() as u8).write(w)?;
530+
for element in self.0.iter() {
531+
element.write(w)?;
532+
}
533+
Ok(())
534+
}
535+
}
536+
impl<T: Readable> Readable for WithLength<Vec<T>, u8> {
537+
#[inline]
538+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
539+
let len = <u8 as Readable>::read(r)? as usize;
540+
let mut result = Vec::with_capacity(len);
541+
for _ in 0..len {
542+
result.push(<T as Readable>::read(r)?);
543+
}
544+
Ok(Self(result, core::marker::PhantomData))
545+
}
546+
}
547+
548+
/// For variable-length values within TLV record where the length is encoded as part of the record.
549+
/// Used to prevent encoding the length twice.
550+
#[derive(Clone)]
551+
pub(crate) struct WithoutLength<T>(pub T);
552+
553+
impl Writeable for WithoutLength<String> {
554+
#[inline]
555+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
556+
w.write_all(self.0.as_bytes())
557+
}
558+
}
559+
impl Readable for WithoutLength<String> {
560+
#[inline]
561+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
562+
let v: VecReadWrapper<u8> = Readable::read(r)?;
563+
Ok(Self(String::from_utf8(v.0).map_err(|_| DecodeError::InvalidValue)?))
564+
}
565+
}
566+
567+
impl<T: Writeable> Writeable for WithoutLength<Vec<T>> {
568+
#[inline]
569+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
570+
VecWriteWrapper(&self.0).write(w)
571+
}
572+
}
573+
impl<T: Readable> Readable for WithoutLength<Vec<T>> {
574+
#[inline]
575+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
576+
Ok(Self(<VecReadWrapper<T> as Readable>::read(r)?.0))
577+
}
578+
}
579+
519580
// HashMap
520581
impl<K, V> Writeable for HashMap<K, V>
521582
where K: Writeable + Eq + Hash,

0 commit comments

Comments
 (0)