1#![warn(missing_docs)]
17
18extern crate self as wolfram_serialize;
21
22pub mod complex;
23pub mod constants;
24pub mod errors;
25pub mod from_wxf;
26pub mod numeric_in;
27pub mod reader;
28pub mod strategy;
29pub mod to_wxf;
30pub mod writer;
31pub mod wxf;
32
33pub use crate::errors::Error;
34
35pub use crate::complex::{Complex, Complex32, Complex64};
36
37pub use crate::constants::{
38 ExpressionEnum, HeaderEnum, NumericArrayEnum, PackedArrayEnum,
39};
40pub use crate::from_wxf::FromWXF;
41pub use crate::reader::{Reader, SliceReader};
42pub use crate::to_wxf::{ToWXF, WxfStruct};
43pub use crate::writer::Writer;
44pub use crate::wxf::reader::WxfReader;
45pub use crate::wxf::writer::WxfWriter;
46pub use wolfram_serialize_macros::{Failure, FromWXF, ToWXF};
49
50#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
52pub enum CompressionLevel {
53 Fastest,
55 Default,
57 Best,
59 Level(u8),
61}
62
63impl CompressionLevel {
64 pub(crate) fn to_u8(self) -> u8 {
65 match self {
66 CompressionLevel::Fastest => 1,
67 CompressionLevel::Default => 6,
68 CompressionLevel::Best => 9,
69 CompressionLevel::Level(n) => n.min(9),
70 }
71 }
72}
73
74pub fn to_wxf<T: ToWXF + ?Sized>(
89 value: &T,
90 compression: impl Into<Option<CompressionLevel>>,
91) -> Result<Vec<u8>, Error> {
92 use crate::constants::HeaderEnum;
93
94 let ver = HeaderEnum::Version as u8;
99 let sep = HeaderEnum::Separator as u8;
100 match compression.into() {
101 None => {
102 let out = vec![ver, sep];
103 let mut w = WxfWriter::new(out);
104 value.to_wxf(&mut w)?;
105 Ok(w.into_inner())
106 },
107 Some(level) => {
108 use flate2::write::ZlibEncoder;
109 use flate2::Compression;
110
111 let out = vec![ver, HeaderEnum::Compress as u8, sep];
112 let encoder =
113 ZlibEncoder::new(out, Compression::new(u32::from(level.to_u8())));
114 let mut w = WxfWriter::new(encoder);
115 value.to_wxf(&mut w)?;
116 Ok(w.into_inner().finish()?)
117 },
118 }
119}
120
121fn strip_header(bytes: &[u8]) -> Result<std::borrow::Cow<'_, [u8]>, Error> {
124 use std::io::Read;
125
126 use crate::constants::HeaderEnum;
127
128 if bytes.len() < 2 {
129 return Err(Error::invalid(
130 "byte stream too short for WXF header".into(),
131 ));
132 }
133 if bytes[0] != HeaderEnum::Version as u8 {
134 return Err(Error::invalid(format!(
135 "WXF header version mismatch: expected {:?}, got {:?}",
136 HeaderEnum::Version as u8 as char,
137 bytes[0] as char
138 )));
139 }
140 if bytes[1] == HeaderEnum::Compress as u8 {
141 if bytes.len() < 3 || bytes[2] != HeaderEnum::Separator as u8 {
142 return Err(Error::invalid("WXF compressed header truncated".into()));
143 }
144 let mut decoded = Vec::new();
145 flate2::read::ZlibDecoder::new(&bytes[3..])
146 .read_to_end(&mut decoded)
147 .map_err(|e| Error::invalid(format!("zlib decompress failed: {}", e)))?;
148 Ok(std::borrow::Cow::Owned(decoded))
149 } else if bytes[1] == HeaderEnum::Separator as u8 {
150 Ok(std::borrow::Cow::Borrowed(&bytes[2..]))
151 } else {
152 Err(Error::invalid(format!(
153 "WXF header separator mismatch: expected ':' or 'C', got {:?}",
154 bytes[1] as char
155 )))
156 }
157}
158
159pub fn read_wxf<T>(
163 bytes: &[u8],
164 f: impl for<'a> FnOnce(&mut WxfReader<SliceReader<'a>>) -> Result<T, Error>,
165) -> Result<T, Error> {
166 let payload = strip_header(bytes)?;
167 let mut r = WxfReader::new(SliceReader::new(&payload));
168 f(&mut r)
169}
170
171pub fn from_wxf<T: for<'de> FromWXF<'de>>(bytes: &[u8]) -> Result<T, Error> {
177 read_wxf(bytes, |r| T::from_wxf(r))
178}
179
180pub fn from_wxf_ref<'de, T: FromWXF<'de>>(bytes: &'de [u8]) -> Result<T, Error> {
186 use crate::constants::HeaderEnum;
187
188 if bytes.len() < 2 || bytes[0] != HeaderEnum::Version as u8 {
189 return Err(Error::invalid("not a WXF stream".into()));
190 }
191 if bytes[1] == HeaderEnum::Compress as u8 {
192 return Err(Error::invalid(
193 "from_wxf_ref requires uncompressed (8:) WXF — borrowed views can't \
194 point into a decompressed buffer"
195 .into(),
196 ));
197 }
198 if bytes[1] != HeaderEnum::Separator as u8 {
199 return Err(Error::invalid("malformed WXF header".into()));
200 }
201 let payload: &'de [u8] = &bytes[2..];
202 let mut r = WxfReader::new(SliceReader::new(payload));
203 T::from_wxf(&mut r)
204}