Skip to main content

oxihuman_export/
thrift_export.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Apache Thrift binary protocol encoding stub.
6
7/// Thrift field types.
8#[allow(dead_code)]
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10#[repr(u8)]
11pub enum ThriftType {
12    Stop = 0,
13    Bool = 2,
14    Byte = 3,
15    Double = 4,
16    I16 = 6,
17    I32 = 8,
18    I64 = 10,
19    String = 11,
20    Struct = 12,
21    Map = 13,
22    Set = 14,
23    List = 15,
24}
25
26/// A Thrift binary encoder.
27#[allow(dead_code)]
28#[derive(Debug, Clone, Default)]
29pub struct ThriftEncoder {
30    pub buf: Vec<u8>,
31}
32
33impl ThriftEncoder {
34    #[allow(dead_code)]
35    pub fn new() -> Self {
36        ThriftEncoder::default()
37    }
38
39    /// Write a field header (type + field id).
40    #[allow(dead_code)]
41    pub fn write_field_begin(&mut self, ftype: ThriftType, field_id: i16) {
42        self.buf.push(ftype as u8);
43        self.buf.extend_from_slice(&field_id.to_be_bytes());
44    }
45
46    /// Write field stop marker.
47    #[allow(dead_code)]
48    pub fn write_field_stop(&mut self) {
49        self.buf.push(ThriftType::Stop as u8);
50    }
51
52    /// Write an i32 value.
53    #[allow(dead_code)]
54    pub fn write_i32(&mut self, val: i32) {
55        self.buf.extend_from_slice(&val.to_be_bytes());
56    }
57
58    /// Write an i64 value.
59    #[allow(dead_code)]
60    pub fn write_i64(&mut self, val: i64) {
61        self.buf.extend_from_slice(&val.to_be_bytes());
62    }
63
64    /// Write a bool value.
65    #[allow(dead_code)]
66    pub fn write_bool(&mut self, val: bool) {
67        self.buf.push(if val { 1 } else { 0 });
68    }
69
70    /// Write a string (length-prefixed).
71    #[allow(dead_code)]
72    pub fn write_string(&mut self, s: &str) {
73        self.buf.extend_from_slice(&(s.len() as i32).to_be_bytes());
74        self.buf.extend_from_slice(s.as_bytes());
75    }
76
77    /// Write a double.
78    #[allow(dead_code)]
79    pub fn write_double(&mut self, val: f64) {
80        self.buf.extend_from_slice(&val.to_bits().to_be_bytes());
81    }
82
83    /// Byte length.
84    #[allow(dead_code)]
85    pub fn len(&self) -> usize {
86        self.buf.len()
87    }
88
89    /// Is empty.
90    #[allow(dead_code)]
91    pub fn is_empty(&self) -> bool {
92        self.buf.is_empty()
93    }
94
95    /// Get encoded bytes.
96    #[allow(dead_code)]
97    pub fn as_bytes(&self) -> &[u8] {
98        &self.buf
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[test]
107    fn new_is_empty() {
108        let enc = ThriftEncoder::new();
109        assert!(enc.is_empty());
110    }
111
112    #[test]
113    fn write_field_begin_three_bytes() {
114        let mut enc = ThriftEncoder::new();
115        enc.write_field_begin(ThriftType::I32, 1);
116        assert_eq!(enc.len(), 3);
117    }
118
119    #[test]
120    fn write_field_stop_one_byte() {
121        let mut enc = ThriftEncoder::new();
122        enc.write_field_stop();
123        assert_eq!(enc.buf[0], 0);
124    }
125
126    #[test]
127    fn write_i32_four_bytes() {
128        let mut enc = ThriftEncoder::new();
129        enc.write_i32(42);
130        assert_eq!(enc.len(), 4);
131    }
132
133    #[test]
134    fn write_i64_eight_bytes() {
135        let mut enc = ThriftEncoder::new();
136        enc.write_i64(1_000_000);
137        assert_eq!(enc.len(), 8);
138    }
139
140    #[test]
141    fn write_bool_one_byte() {
142        let mut enc = ThriftEncoder::new();
143        enc.write_bool(true);
144        assert_eq!(enc.buf[0], 1);
145    }
146
147    #[test]
148    fn write_string_length_prefixed() {
149        let mut enc = ThriftEncoder::new();
150        enc.write_string("hi");
151        assert_eq!(enc.len(), 6);
152    }
153
154    #[test]
155    fn write_double_eight_bytes() {
156        let mut enc = ThriftEncoder::new();
157        enc.write_double(std::f64::consts::PI);
158        assert_eq!(enc.len(), 8);
159    }
160
161    #[test]
162    fn as_bytes_matches_buf() {
163        let mut enc = ThriftEncoder::new();
164        enc.write_i32(1);
165        assert_eq!(enc.as_bytes(), &enc.buf[..]);
166    }
167
168    #[test]
169    fn full_field_round_trip() {
170        let mut enc = ThriftEncoder::new();
171        enc.write_field_begin(ThriftType::I32, 1);
172        enc.write_i32(99);
173        enc.write_field_stop();
174        assert_eq!(enc.len(), 8);
175    }
176}