1use serde::Serialize;
4#[cfg(feature = "unstable-v2")]
5use usize_cast::IntoUsize as _;
6
7use super::model::{BlobInfo, DecodeHint};
8use crate::Decoder;
9use crate::decoder::RawStream;
10
11#[derive(Debug, Clone, PartialEq, Serialize)]
16#[serde(
17 tag = "kind",
18 rename_all = "camelCase",
19 rename_all_fields = "camelCase"
20)]
21pub enum DecodedBlob {
22 Numbers {
24 values: Vec<f64>,
25 truncated_from: Option<u32>,
27 },
28 #[serde(rename = "bigints")]
30 BigInts {
31 values: Vec<i128>,
32 truncated_from: Option<u32>,
33 },
34 Bools {
35 values: Vec<bool>,
36 truncated_from: Option<u32>,
37 },
38 Text { value: String },
40 Binary { len: u32 },
42 Error { message: String },
44}
45
46pub fn decode_blob(
52 info: BlobInfo,
53 data: &[u8],
54 max_values: usize,
55 dec: &mut Decoder,
56) -> DecodedBlob {
57 dec.reset_budget();
59 let meta = info.meta;
60 match info.hint {
61 DecodeHint::Presence => match RawStream::new(meta, data).decode_bitvec(dec) {
62 Ok(bits) => bools(bits.iter().by_vals().collect(), max_values),
63 Err(e) => error(&e),
64 },
65 #[cfg(feature = "unstable-v2")]
66 DecodeHint::PresenceCoded(coding) => {
67 use crate::codecs::presence_coding::{Unmetered, read};
68 match read(data, meta.num_values, coding, &mut Unmetered) {
69 Ok((_, bits)) => bools(bits.iter().by_vals().collect(), max_values),
70 Err(e) => DecodedBlob::Error {
71 message: e.to_string(),
72 },
73 }
74 }
75 #[cfg(feature = "unstable-v2")]
76 DecodeHint::PackedBits => {
77 let n = meta.num_values.into_usize();
78 let available = data.len() * 8;
79 if available < n {
80 return DecodedBlob::Error {
81 message: format!("needs {n} bits, got {available}"),
82 };
83 }
84 bools(
85 (0..n).map(|i| data[i / 8] >> (i % 8) & 1 == 1).collect(),
86 max_values,
87 )
88 }
89 DecodeHint::Bool => match RawStream::new(meta, data).decode_bools(dec) {
90 Ok(v) => bools(v, max_values),
91 Err(e) => error(&e),
92 },
93 DecodeHint::I32 => numbers(
94 RawStream::new(meta, data).decode_ints::<i32>(dec),
95 max_values,
96 ),
97 DecodeHint::U32 => numbers(
98 RawStream::new(meta, data).decode_ints::<u32>(dec),
99 max_values,
100 ),
101 DecodeHint::F32 => numbers(
102 RawStream::new(meta, data).decode_floats::<f32>(dec),
103 max_values,
104 ),
105 DecodeHint::F64 => numbers(
106 RawStream::new(meta, data).decode_floats::<f64>(dec),
107 max_values,
108 ),
109 DecodeHint::I64 => bigints(
110 RawStream::new(meta, data).decode_ints::<i64>(dec),
111 max_values,
112 ),
113 DecodeHint::U64 => bigints(
114 RawStream::new(meta, data).decode_ints::<u64>(dec),
115 max_values,
116 ),
117 #[cfg(feature = "unstable-v2")]
118 DecodeHint::Alp(params) => bigints(
119 RawStream::new(meta, data).decode_alp_codes(params, dec),
120 max_values,
121 ),
122 DecodeHint::Bytes => match std::str::from_utf8(data) {
123 Ok(s) => DecodedBlob::Text {
124 value: s.to_string(),
125 },
126 Err(_) => DecodedBlob::Binary {
127 len: count(data.len()),
128 },
129 },
130 }
131}
132
133fn numbers<T: Into<f64>>(res: crate::MltResult<Vec<T>>, max_values: usize) -> DecodedBlob {
134 match res {
135 Ok(v) => {
136 let (v, truncated_from) = cap(v, max_values);
137 DecodedBlob::Numbers {
138 values: v.into_iter().map(Into::into).collect(),
139 truncated_from,
140 }
141 }
142 Err(e) => error(&e),
143 }
144}
145
146fn bigints<T: Into<i128>>(res: crate::MltResult<Vec<T>>, max_values: usize) -> DecodedBlob {
147 match res {
148 Ok(v) => {
149 let (v, truncated_from) = cap(v, max_values);
150 DecodedBlob::BigInts {
151 values: v.into_iter().map(Into::into).collect(),
152 truncated_from,
153 }
154 }
155 Err(e) => error(&e),
156 }
157}
158
159fn bools(v: Vec<bool>, max_values: usize) -> DecodedBlob {
160 let (values, truncated_from) = cap(v, max_values);
161 DecodedBlob::Bools {
162 values,
163 truncated_from,
164 }
165}
166
167fn error(e: &crate::MltError) -> DecodedBlob {
168 DecodedBlob::Error {
169 message: e.to_string(),
170 }
171}
172
173fn cap<T>(mut values: Vec<T>, max_values: usize) -> (Vec<T>, Option<u32>) {
175 let total = values.len();
176 if max_values == 0 || total <= max_values {
177 return (values, None);
178 }
179 values.truncate(max_values);
180 (values, Some(count(total)))
181}
182
183fn count(n: usize) -> u32 {
184 u32::try_from(n).unwrap_or(u32::MAX)
185}