1#[cfg(feature = "decoder")]
4pub mod decoder;
5
6#[cfg(feature = "encoder")]
7pub mod encoder;
8
9pub mod codec;
10
11pub mod protobuf_conversions;
12
13#[cfg(feature = "encoder")]
14#[cfg(not(target_arch = "wasm32"))]
15mod file_sink;
16
17#[cfg(feature = "stream_from_http")]
18pub mod stream_rrd_from_http;
19
20#[cfg(feature = "encoder")]
23#[cfg(not(target_arch = "wasm32"))]
24pub use file_sink::{FileSink, FileSinkError};
25
26#[cfg(any(feature = "encoder", feature = "decoder"))]
29const RRD_HEADER: &[u8; 4] = b"RRF2";
30
31#[cfg(feature = "decoder")]
32const OLD_RRD_HEADERS: &[[u8; 4]] = &[*b"RRF0", *b"RRF1"];
33
34#[derive(Clone, Copy, Debug, PartialEq, Eq)]
38#[repr(u8)]
39pub enum Compression {
40 Off = 0,
41
42 LZ4 = 1,
44}
45
46#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48#[repr(u8)]
49pub enum Serializer {
50 Protobuf = 2,
51}
52
53#[derive(Clone, Copy, Debug, PartialEq, Eq)]
54pub struct EncodingOptions {
55 pub compression: Compression,
56 pub serializer: Serializer,
57}
58
59impl EncodingOptions {
60 pub const PROTOBUF_COMPRESSED: Self = Self {
61 compression: Compression::LZ4,
62 serializer: Serializer::Protobuf,
63 };
64 pub const PROTOBUF_UNCOMPRESSED: Self = Self {
65 compression: Compression::Off,
66 serializer: Serializer::Protobuf,
67 };
68
69 pub fn from_bytes(bytes: [u8; 4]) -> Result<Self, OptionsError> {
70 match bytes {
71 [compression, serializer, 0, 0] => {
72 let compression = match compression {
73 0 => Compression::Off,
74 1 => Compression::LZ4,
75 _ => return Err(OptionsError::UnknownCompression(compression)),
76 };
77 let serializer = match serializer {
78 1 => return Err(OptionsError::RemovedMsgPackSerializer),
79 2 => Serializer::Protobuf,
80 _ => return Err(OptionsError::UnknownSerializer(serializer)),
81 };
82 Ok(Self {
83 compression,
84 serializer,
85 })
86 }
87 _ => Err(OptionsError::UnknownReservedBytes),
88 }
89 }
90
91 pub fn to_bytes(self) -> [u8; 4] {
92 [
93 self.compression as u8,
94 self.serializer as u8,
95 0, 0, ]
98 }
99}
100
101#[derive(thiserror::Error, Debug)]
103#[allow(clippy::enum_variant_names)]
104pub enum OptionsError {
105 #[error("Reserved bytes not zero")]
106 UnknownReservedBytes,
107
108 #[error("Unknown compression: {0}")]
109 UnknownCompression(u8),
110
111 #[error(
113 "You are trying to load an old .rrd file that's not supported by this version of Rerun."
114 )]
115 RemovedMsgPackSerializer,
116
117 #[error("Unknown serializer: {0}")]
118 UnknownSerializer(u8),
119}
120
121#[cfg(any(feature = "encoder", feature = "decoder"))]
122#[derive(Debug, Clone, Copy)]
123pub(crate) struct FileHeader {
124 pub magic: [u8; 4],
125 pub version: [u8; 4],
126 pub options: EncodingOptions,
127}
128
129#[cfg(any(feature = "encoder", feature = "decoder"))]
130impl FileHeader {
131 #[cfg(feature = "decoder")]
132 pub const SIZE: usize = 12;
133
134 #[cfg(feature = "encoder")]
135 pub fn encode(&self, write: &mut impl std::io::Write) -> Result<(), encoder::EncodeError> {
136 write
137 .write_all(&self.magic)
138 .map_err(encoder::EncodeError::Write)?;
139 write
140 .write_all(&self.version)
141 .map_err(encoder::EncodeError::Write)?;
142 write
143 .write_all(&self.options.to_bytes())
144 .map_err(encoder::EncodeError::Write)?;
145 Ok(())
146 }
147
148 #[cfg(feature = "decoder")]
149 pub fn decode(read: &mut impl std::io::Read) -> Result<Self, decoder::DecodeError> {
150 let to_array_4b = |slice: &[u8]| slice.try_into().expect("always returns an Ok() variant");
151
152 let mut buffer = [0_u8; Self::SIZE];
153 read.read_exact(&mut buffer)
154 .map_err(decoder::DecodeError::Read)?;
155 let magic = to_array_4b(&buffer[0..4]);
156 let version = to_array_4b(&buffer[4..8]);
157 let options = EncodingOptions::from_bytes(to_array_4b(&buffer[8..]))?;
158 Ok(Self {
159 magic,
160 version,
161 options,
162 })
163 }
164}