Skip to main content

usage_monitor_cli/provider/
proto.rs

1//! Minimal protobuf wire-format helpers shared by the `windsurf` (Connect) and
2//! `grok` (gRPC-Web) providers, which speak protobuf rather than JSON.
3//!
4//! Only the wire types the two providers use are supported. Everything returns
5//! `Option`/bounded results — malformed input yields `None` rather than panics.
6
7/// Protobuf wire types.
8pub const WIRE_VARINT: u8 = 0;
9pub const WIRE_FIXED64: u8 = 1;
10pub const WIRE_LEN: u8 = 2;
11pub const WIRE_FIXED32: u8 = 5;
12
13/// A streaming reader over a protobuf message body.
14pub struct Reader<'a> {
15    data: &'a [u8],
16    pos: usize,
17}
18
19impl<'a> Reader<'a> {
20    pub fn new(data: &'a [u8]) -> Self {
21        Self { data, pos: 0 }
22    }
23
24    pub fn done(&self) -> bool {
25        self.pos >= self.data.len()
26    }
27
28    /// Reads a base-128 varint. Returns `None` on truncation.
29    pub fn read_varint(&mut self) -> Option<u64> {
30        let mut result: u64 = 0;
31        let mut shift = 0;
32        loop {
33            let byte = *self.data.get(self.pos)?;
34            self.pos += 1;
35            result |= ((byte & 0x7f) as u64) << shift;
36            if byte & 0x80 == 0 {
37                return Some(result);
38            }
39            shift += 7;
40            if shift >= 64 {
41                return None;
42            }
43        }
44    }
45
46    /// Reads a field key, returning `(field_number, wire_type)`.
47    pub fn next_key(&mut self) -> Option<(u32, u8)> {
48        let key = self.read_varint()?;
49        let field = (key >> 3) as u32;
50        let wire = (key & 0x07) as u8;
51        if field == 0 {
52            return None;
53        }
54        Some((field, wire))
55    }
56
57    /// Reads a length-delimited byte slice.
58    pub fn read_len(&mut self) -> Option<&'a [u8]> {
59        let len = self.read_varint()? as usize;
60        let end = self.pos.checked_add(len)?;
61        if end > self.data.len() {
62            return None;
63        }
64        let slice = &self.data[self.pos..end];
65        self.pos = end;
66        Some(slice)
67    }
68
69    pub fn read_fixed32(&mut self) -> Option<u32> {
70        let end = self.pos.checked_add(4)?;
71        if end > self.data.len() {
72            return None;
73        }
74        let b = &self.data[self.pos..end];
75        self.pos = end;
76        Some(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
77    }
78
79    pub fn read_fixed64(&mut self) -> Option<u64> {
80        let end = self.pos.checked_add(8)?;
81        if end > self.data.len() {
82            return None;
83        }
84        let b = &self.data[self.pos..end];
85        self.pos = end;
86        Some(u64::from_le_bytes([
87            b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
88        ]))
89    }
90
91    /// Skips the body of a field with the given wire type. Returns `None` on a
92    /// malformed/unsupported wire type.
93    pub fn skip(&mut self, wire: u8) -> Option<()> {
94        match wire {
95            WIRE_VARINT => self.read_varint().map(|_| ()),
96            WIRE_FIXED64 => self.read_fixed64().map(|_| ()),
97            WIRE_LEN => self.read_len().map(|_| ()),
98            WIRE_FIXED32 => self.read_fixed32().map(|_| ()),
99            _ => None,
100        }
101    }
102}
103
104/// Appends a varint to `out`.
105pub fn encode_varint(mut value: u64, out: &mut Vec<u8>) {
106    while value >= 0x80 {
107        out.push(((value & 0x7f) | 0x80) as u8);
108        value >>= 7;
109    }
110    out.push(value as u8);
111}
112
113/// Appends a field key `(field_number << 3) | wire_type`.
114pub fn encode_key(field: u32, wire: u8, out: &mut Vec<u8>) {
115    encode_varint(((field as u64) << 3) | wire as u64, out);
116}
117
118/// Appends a length-delimited string field.
119pub fn encode_string_field(field: u32, value: &str, out: &mut Vec<u8>) {
120    encode_key(field, WIRE_LEN, out);
121    encode_varint(value.len() as u64, out);
122    out.extend_from_slice(value.as_bytes());
123}
124
125/// Appends a varint field.
126pub fn encode_varint_field(field: u32, value: u64, out: &mut Vec<u8>) {
127    encode_key(field, WIRE_VARINT, out);
128    encode_varint(value, out);
129}
130
131#[cfg(test)]
132mod tests {
133    use super::*;
134
135    #[test]
136    fn test_varint_roundtrip() {
137        for v in [0u64, 1, 127, 128, 300, 16384, u32::MAX as u64, u64::MAX] {
138            let mut buf = Vec::new();
139            encode_varint(v, &mut buf);
140            let mut r = Reader::new(&buf);
141            assert_eq!(r.read_varint(), Some(v));
142            assert!(r.done());
143        }
144    }
145
146    #[test]
147    fn test_field_encode_decode() {
148        let mut buf = Vec::new();
149        encode_string_field(1, "tok", &mut buf);
150        encode_varint_field(2, 1, &mut buf);
151
152        let mut r = Reader::new(&buf);
153        assert_eq!(r.next_key(), Some((1, WIRE_LEN)));
154        assert_eq!(r.read_len(), Some(&b"tok"[..]));
155        assert_eq!(r.next_key(), Some((2, WIRE_VARINT)));
156        assert_eq!(r.read_varint(), Some(1));
157        assert!(r.done());
158    }
159
160    #[test]
161    fn test_skip() {
162        let mut buf = Vec::new();
163        encode_varint_field(1, 42, &mut buf);
164        encode_string_field(2, "keep", &mut buf);
165        let mut r = Reader::new(&buf);
166        let (f, w) = r.next_key().unwrap();
167        assert_eq!(f, 1);
168        r.skip(w).unwrap();
169        assert_eq!(r.next_key(), Some((2, WIRE_LEN)));
170        assert_eq!(r.read_len(), Some(&b"keep"[..]));
171    }
172
173    #[test]
174    fn test_truncated_varint_is_none() {
175        let mut r = Reader::new(&[0x80]); // continuation bit set, no next byte
176        assert_eq!(r.read_varint(), None);
177    }
178
179    #[test]
180    fn test_read_len_out_of_bounds() {
181        // length says 10 but only 2 bytes follow
182        let mut r = Reader::new(&[0x0a, b'h', b'i']);
183        let (_f, _w) = r.next_key().unwrap();
184        assert_eq!(r.read_len(), None);
185    }
186
187    #[test]
188    fn test_fixed32() {
189        let bytes = 3.5f32.to_bits().to_le_bytes();
190        let mut r = Reader::new(&bytes);
191        assert_eq!(r.read_fixed32().map(f32::from_bits), Some(3.5));
192    }
193}