Skip to main content

taproot_assets_types/
tlv.rs

1use alloc::{string::String, vec, vec::Vec};
2use bitcoin::io::{self as bitcoin_io, Read};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub struct Type(pub u64);
6
7impl Type {
8    pub fn is_odd(self) -> bool {
9        self.0 % 2 != 0
10    }
11    pub fn is_even(self) -> bool {
12        self.0 % 2 == 0
13    }
14}
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct Record {
18    tlv_type: Type,
19    value: Vec<u8>,
20}
21
22impl Record {
23    pub fn tlv_type(&self) -> Type {
24        self.tlv_type
25    }
26
27    pub fn value(&self) -> &[u8] {
28        &self.value
29    }
30
31    pub fn value_reader(&self) -> bitcoin_io::Cursor<&[u8]> {
32        bitcoin_io::Cursor::new(&self.value)
33    }
34}
35
36pub struct Stream<R: Read> {
37    reader: R,
38}
39
40impl<R: Read> Stream<R> {
41    pub fn new(reader: R) -> Self {
42        Stream { reader }
43    }
44
45    fn read_u8_manual(&mut self) -> Result<u8, crate::error::Error> {
46        let mut buf = [0; 1];
47        self.reader
48            .read_exact(&mut buf)
49            .map_err(crate::error::Error::Io)?;
50        Ok(buf[0])
51    }
52
53    fn read_u16_manual_be(&mut self) -> Result<u16, crate::error::Error> {
54        let mut buf = [0; 2];
55        self.reader
56            .read_exact(&mut buf)
57            .map_err(crate::error::Error::Io)?;
58        Ok(u16::from_be_bytes(buf))
59    }
60
61    fn read_u32_manual_be(&mut self) -> Result<u32, crate::error::Error> {
62        let mut buf = [0; 4];
63        self.reader
64            .read_exact(&mut buf)
65            .map_err(crate::error::Error::Io)?;
66        Ok(u32::from_be_bytes(buf))
67    }
68
69    fn read_u64_manual_be(&mut self) -> Result<u64, crate::error::Error> {
70        let mut buf = [0; 8];
71        self.reader
72            .read_exact(&mut buf)
73            .map_err(crate::error::Error::Io)?;
74        Ok(u64::from_be_bytes(buf))
75    }
76
77    // Helper to read a var_int (compact size uin)
78    fn read_var_int(&mut self) -> Result<u64, crate::error::Error> {
79        let first_byte = self.read_u8_manual()?;
80        match first_byte {
81            0..=0xFC => Ok(first_byte as u64),
82            0xFD => Ok(self.read_u16_manual_be()? as u64),
83            0xFE => Ok(self.read_u32_manual_be()? as u64),
84            0xFF => Ok(self.read_u64_manual_be()?),
85        }
86    }
87
88    pub fn next_record(&mut self) -> Result<Option<Record>, String> {
89        let tlv_type = match self.read_var_int() {
90            Ok(val) => Type(val),
91            Err(crate::error::Error::Io(_)) => return Ok(None), // Clean EOF or any I/O error when
92            // starting to read a type.
93            Err(e) => return Err(alloc::format!("Failed to read TLV type: {:?}", e)),
94        };
95
96        let length = match self.read_var_int() {
97            Ok(val) => val,
98            Err(e) => {
99                return Err(alloc::format!(
100                    "Failed to read TLV length for type {:?}: {:?}",
101                    tlv_type,
102                    e
103                ));
104            }
105        };
106
107        if length > (1_i32 << 20) as u64 {
108            // Limit to ~1MB for safety
109            return Err(alloc::format!(
110                "TLV record too large: {} bytes for type {:?}",
111                length,
112                tlv_type
113            ));
114        }
115
116        let mut value = vec![0; length as usize];
117        match self.reader.read_exact(&mut value) {
118            Ok(_) => Ok(Some(Record { tlv_type, value })),
119            Err(e) => Err(alloc::format!(
120                "Failed to read TLV value for type {:?} (length {}): {:?}",
121                tlv_type,
122                length,
123                e
124            )),
125        }
126    }
127}
128
129// Placeholder for a generic TLV decoder trait if needed later.
130// pub trait Decoder: Sized {
131//    fn decode<R: Read>(r: R) -> Result<Self, Error>;
132// }
133
134// Dummy Value type, not strictly needed if Record::value_reader() is used.
135pub type Value<'a> = &'a [u8];