Skip to main content

compactly/v1/
mod.rs

1//! The `v1` format of compactly.
2//!
3//! This format should be unmodified after the 1.0 release, except for addition
4//! of support for new strategies, which won't change the binary format of types
5//! that don't use those strategies.
6pub use compactly_derive::EncodeV1 as Encode;
7use std::io::{Read, Write};
8
9mod adapt;
10mod arc;
11mod arith;
12mod array;
13mod bit_context;
14mod bits;
15mod bools;
16mod byte;
17mod bytes;
18mod floats;
19#[cfg(feature = "generate_bit_context")]
20pub mod generate_bit_context;
21mod ints;
22mod low_cardinality;
23mod maps;
24mod option;
25mod sets;
26mod string;
27mod tuples;
28mod ulessthan;
29mod usizes;
30mod vecs;
31
32use crate::{LowCardinality, Small};
33pub use adapt::{Reader, Writer};
34pub use ulessthan::ULessThan;
35
36/// Trait for types that can be compactly encoded.
37///
38/// Normally you will derive this for your own types, although it can be
39/// implemented manually.
40pub trait Encode: Sized {
41    /// Context storing probability model for this type.
42    type Context: Default + Clone;
43
44    /// Encode this value to the [`Writer<W>`].
45    fn encode<W: Write>(
46        &self,
47        writer: &mut Writer<W>,
48        ctx: &mut Self::Context,
49    ) -> Result<(), std::io::Error>;
50
51    /// Extimate the number of millibits required for this value.
52    ///
53    /// Returns `None` if this estimation has not been implemented.
54    #[expect(unused_variables)]
55    fn millibits(&self, ctx: &mut Self::Context) -> Option<usize> {
56        // let mut counter = Writer::new(adapt::Counter::default());
57        // self.encode(&mut counter, ctx).ok();
58        // counter.len() * 8000
59        None
60    }
61
62    /// Decode value from ['Reader<R>`].
63    fn decode<R: Read>(
64        reader: &mut Reader<R>,
65        ctx: &mut Self::Context,
66    ) -> Result<Self, std::io::Error>;
67}
68
69/// Encode the `value` into a `Vec<u8>` of bytes.`
70pub fn encode<T: Encode>(value: &T) -> Vec<u8> {
71    let mut out = Vec::with_capacity(8);
72    {
73        let mut writer = Writer::new(&mut out);
74        value
75            .encode(&mut writer, &mut T::Context::default())
76            .unwrap();
77        writer.finish().unwrap();
78    }
79    out
80}
81
82/// Decode a value of this type from `bytes`.
83///
84/// Returns `None` if the bytes do not encode a valid value.
85pub fn decode<T: Encode>(mut bytes: &[u8]) -> Option<T> {
86    let mut reader = Reader::new(&mut bytes).unwrap();
87    T::decode(&mut reader, &mut T::Context::default()).ok()
88}
89
90/// An encoding strategy for type `T`.
91///
92/// You *can* implement this for your own types, if you want them to support
93/// e.g. `Small` encodings.  But I expect this to be unusual.  It would be
94/// possible to create a `Derive` macro for this, but I don't think it is
95/// needed.  If you want such a macro file an issue.
96///
97/// Note that besides implementing existing strategies for your own types, you
98/// can also create entirely new strategies in your crates.  If you do that, you
99/// can use full paths in your derive macros, e.g.
100/// `#[compactly(your_crate::SuperCoolEncodingStratgy]`.
101pub trait EncodingStrategy<T>: Copy {
102    /// The conext (i.e. probability model) for this encoding strategy applied to this type.
103    type Context: Default + Clone;
104
105    /// Encode the value with this strategy.
106    fn encode<W: Write>(
107        value: &T,
108        writer: &mut Writer<W>,
109        ctx: &mut Self::Context,
110    ) -> Result<(), std::io::Error>;
111
112    /// Estimate the size of the encoded value using this stratgy.
113    #[expect(unused_variables)]
114    fn millibits(value: &T, ctx: &mut Self::Context) -> Option<usize> {
115        None
116    }
117
118    /// Decode the value using this strategy.
119    fn decode<R: Read>(
120        reader: &mut Reader<R>,
121        ctx: &mut Self::Context,
122    ) -> Result<T, std::io::Error>;
123}
124
125/// Encode a value with a specific strategy (into a `Vec<u8>`).
126///
127/// I don't expect this to be used in practice, but it can be helpful for
128/// testing.
129pub fn encode_with<T: Encode, S: EncodingStrategy<T>>(_: S, value: &T) -> Vec<u8> {
130    let mut out = Vec::with_capacity(8);
131    {
132        let mut writer = Writer::<&mut Vec<u8>>::new(&mut out);
133        S::encode(value, &mut writer, &mut S::Context::default()).unwrap();
134        writer.finish().unwrap();
135    }
136    out
137}
138
139/// Decode a value with a specific strategy (from a bytes slice).
140///
141/// I don't expect this to be used in practice, but it can be helpful for
142/// testing.
143pub fn decode_with<T: Encode, S: EncodingStrategy<T>>(_: S, mut bytes: &[u8]) -> Option<T> {
144    let mut reader = Reader::new(&mut bytes).unwrap();
145    S::decode(&mut reader, &mut S::Context::default()).ok()
146}
147
148impl<T, S: EncodingStrategy<T>> Encode for crate::Encoded<T, S> {
149    type Context = S::Context;
150    #[inline]
151    fn encode<W: std::io::Write>(
152        &self,
153        writer: &mut Writer<W>,
154        ctx: &mut Self::Context,
155    ) -> Result<(), std::io::Error> {
156        S::encode(&self.value, writer, ctx)
157    }
158    #[inline]
159    fn millibits(&self, ctx: &mut Self::Context) -> Option<usize> {
160        S::millibits(&self.value, ctx)
161    }
162    #[inline]
163    fn decode<R: std::io::Read>(
164        reader: &mut Reader<R>,
165        ctx: &mut Self::Context,
166    ) -> Result<Self, std::io::Error> {
167        Ok(Self {
168            value: S::decode(reader, ctx)?,
169            _phantom: std::marker::PhantomData,
170        })
171    }
172}
173
174impl<T: Encode> EncodingStrategy<T> for crate::Normal {
175    type Context = <T as Encode>::Context;
176    #[inline]
177    fn encode<W: Write>(
178        value: &T,
179        writer: &mut Writer<W>,
180        ctx: &mut Self::Context,
181    ) -> Result<(), std::io::Error> {
182        value.encode(writer, ctx)
183    }
184    fn millibits(value: &T, ctx: &mut Self::Context) -> Option<usize> {
185        value.millibits(ctx)
186    }
187    fn decode<R: Read>(
188        reader: &mut Reader<R>,
189        ctx: &mut Self::Context,
190    ) -> Result<T, std::io::Error> {
191        T::decode(reader, ctx)
192    }
193}
194
195#[cfg(test)]
196macro_rules! assert_size {
197    ($v:expr, $size:expr) => {
198        let v = $v;
199        let bytes = super::encode(&v);
200        let decoded = super::decode(&bytes);
201        assert_eq!(decoded, Some(v), "decoded value is incorrect");
202        assert_eq!(bytes.len(), $size, "unexpected size");
203    };
204}
205#[cfg(test)]
206pub(crate) use assert_size;
207
208#[cfg(test)]
209macro_rules! assert_bits {
210    ($v:expr, $size:expr) => {
211        let v1 = $v;
212        let bytes = super::encode(&v1);
213        let decoded = super::decode(&bytes);
214        assert_eq!(decoded, Some(v1), "decoded value is incorrect");
215        let v = (
216            ($v, $v, $v, $v, $v, $v, $v, $v),
217            ($v, $v, $v, $v, $v, $v, $v, $v),
218            ($v, $v, $v, $v, $v, $v, $v, $v),
219            ($v, $v, $v, $v, $v, $v, $v, $v),
220            ($v, $v, $v, $v, $v, $v, $v, $v),
221            ($v, $v, $v, $v, $v, $v, $v, $v),
222            ($v, $v, $v, $v, $v, $v, $v, $v),
223            ($v, $v, $v, $v, $v, $v, $v, $v),
224        );
225        let bytes = super::encode(&v);
226        let decoded = super::decode(&bytes);
227        assert_eq!(decoded, Some(v), "decoded tuple value is incorrect");
228        assert_eq!((bytes.len() + 4) / 8, $size, "unexpected number of bits");
229    };
230    ($v:expr, $size:expr, $msg:expr) => {
231        let v1 = $v;
232        let bytes = super::encode(&v1);
233        let decoded = super::decode(&bytes);
234        assert_eq!(decoded, Some(v1), "decoded value is incorrect: {}", $msg);
235        let v = (
236            ($v, $v, $v, $v, $v, $v, $v, $v),
237            ($v, $v, $v, $v, $v, $v, $v, $v),
238            ($v, $v, $v, $v, $v, $v, $v, $v),
239            ($v, $v, $v, $v, $v, $v, $v, $v),
240            ($v, $v, $v, $v, $v, $v, $v, $v),
241            ($v, $v, $v, $v, $v, $v, $v, $v),
242            ($v, $v, $v, $v, $v, $v, $v, $v),
243            ($v, $v, $v, $v, $v, $v, $v, $v),
244        );
245        let bytes = super::encode(&v);
246        let decoded = super::decode(&bytes);
247        assert_eq!(
248            decoded,
249            Some(v),
250            "decoded tuple value is incorrect: {}",
251            $msg
252        );
253        assert_eq!(
254            (bytes.len() + 4) / 8,
255            $size,
256            "unexpected number of bits: {}",
257            $msg
258        );
259    };
260}
261#[cfg(test)]
262pub(crate) use assert_bits;