1use super::*;
16#[cfg(feature = "serde")]
17use alloc::string::{String, ToString};
18#[cfg(feature = "mem_dbg")]
19use mem_dbg::{MemDbg, MemSize};
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
34#[cfg_attr(feature = "mem_dbg", mem_size(flat))]
35#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
36#[non_exhaustive]
37pub enum Codes {
38 Unary,
39 Gamma,
40 Delta,
41 Omega,
42 VByteLe,
43 VByteBe,
44 Zeta(usize),
45 Pi(usize),
46 Golomb(u64),
47 ExpGolomb(usize),
48 Rice(usize),
49}
50
51impl Codes {
52 #[must_use]
77 pub const fn canonicalize(self) -> Self {
78 match self {
79 Self::Zeta(1) | Self::ExpGolomb(0) | Self::Pi(0) => Self::Gamma,
80 Self::Rice(0) | Self::Golomb(1) => Self::Unary,
81 Self::Golomb(b) if b.is_power_of_two() => Self::Rice(b.trailing_zeros() as usize),
82 other => other,
83 }
84 }
85
86 #[inline(always)]
91 pub fn read<E: Endianness, CR: CodesRead<E> + ?Sized>(
92 &self,
93 reader: &mut CR,
94 ) -> Result<u64, CR::Error> {
95 DynamicCodeRead::read(self, reader)
96 }
97
98 #[inline(always)]
103 pub fn write<E: Endianness, CW: CodesWrite<E> + ?Sized>(
104 &self,
105 writer: &mut CW,
106 n: u64,
107 ) -> Result<usize, CW::Error> {
108 DynamicCodeWrite::write(self, writer, n)
109 }
110
111 pub const fn to_code_const(&self) -> Result<usize, DispatchError> {
125 Ok(match self.canonicalize() {
126 Self::Unary => code_consts::UNARY,
127 Self::Gamma => code_consts::GAMMA,
128 Self::Delta => code_consts::DELTA,
129 Self::Omega => code_consts::OMEGA,
130 Self::VByteLe => code_consts::VBYTE_LE,
131 Self::VByteBe => code_consts::VBYTE_BE,
132 Self::Zeta(2) => code_consts::ZETA2,
133 Self::Zeta(3) => code_consts::ZETA3,
134 Self::Zeta(4) => code_consts::ZETA4,
135 Self::Zeta(5) => code_consts::ZETA5,
136 Self::Zeta(6) => code_consts::ZETA6,
137 Self::Zeta(7) => code_consts::ZETA7,
138 Self::Zeta(8) => code_consts::ZETA8,
139 Self::Zeta(9) => code_consts::ZETA9,
140 Self::Zeta(10) => code_consts::ZETA10,
141 Self::Rice(1) => code_consts::RICE1,
142 Self::Rice(2) => code_consts::RICE2,
143 Self::Rice(3) => code_consts::RICE3,
144 Self::Rice(4) => code_consts::RICE4,
145 Self::Rice(5) => code_consts::RICE5,
146 Self::Rice(6) => code_consts::RICE6,
147 Self::Rice(7) => code_consts::RICE7,
148 Self::Rice(8) => code_consts::RICE8,
149 Self::Rice(9) => code_consts::RICE9,
150 Self::Rice(10) => code_consts::RICE10,
151 Self::Pi(1) => code_consts::PI1,
152 Self::Pi(2) => code_consts::PI2,
153 Self::Pi(3) => code_consts::PI3,
154 Self::Pi(4) => code_consts::PI4,
155 Self::Pi(5) => code_consts::PI5,
156 Self::Pi(6) => code_consts::PI6,
157 Self::Pi(7) => code_consts::PI7,
158 Self::Pi(8) => code_consts::PI8,
159 Self::Pi(9) => code_consts::PI9,
160 Self::Pi(10) => code_consts::PI10,
161 Self::Golomb(3) => code_consts::GOLOMB3,
162 Self::Golomb(5) => code_consts::GOLOMB5,
163 Self::Golomb(6) => code_consts::GOLOMB6,
164 Self::Golomb(7) => code_consts::GOLOMB7,
165 Self::Golomb(9) => code_consts::GOLOMB9,
166 Self::Golomb(10) => code_consts::GOLOMB10,
167 Self::ExpGolomb(1) => code_consts::EXP_GOLOMB1,
168 Self::ExpGolomb(2) => code_consts::EXP_GOLOMB2,
169 Self::ExpGolomb(3) => code_consts::EXP_GOLOMB3,
170 Self::ExpGolomb(4) => code_consts::EXP_GOLOMB4,
171 Self::ExpGolomb(5) => code_consts::EXP_GOLOMB5,
172 Self::ExpGolomb(6) => code_consts::EXP_GOLOMB6,
173 Self::ExpGolomb(7) => code_consts::EXP_GOLOMB7,
174 Self::ExpGolomb(8) => code_consts::EXP_GOLOMB8,
175 Self::ExpGolomb(9) => code_consts::EXP_GOLOMB9,
176 Self::ExpGolomb(10) => code_consts::EXP_GOLOMB10,
177 _ => {
178 return Err(DispatchError::UnsupportedCode(*self));
179 }
180 })
181 }
182
183 pub const fn from_code_const(const_code: usize) -> Result<Self, DispatchError> {
190 Ok(match const_code {
191 code_consts::UNARY => Self::Unary,
192 code_consts::GAMMA => Self::Gamma,
193 code_consts::DELTA => Self::Delta,
194 code_consts::OMEGA => Self::Omega,
195 code_consts::VBYTE_LE => Self::VByteLe,
196 code_consts::VBYTE_BE => Self::VByteBe,
197 code_consts::ZETA2 => Self::Zeta(2),
198 code_consts::ZETA3 => Self::Zeta(3),
199 code_consts::ZETA4 => Self::Zeta(4),
200 code_consts::ZETA5 => Self::Zeta(5),
201 code_consts::ZETA6 => Self::Zeta(6),
202 code_consts::ZETA7 => Self::Zeta(7),
203 code_consts::ZETA8 => Self::Zeta(8),
204 code_consts::ZETA9 => Self::Zeta(9),
205 code_consts::ZETA10 => Self::Zeta(10),
206 code_consts::RICE1 => Self::Rice(1),
207 code_consts::RICE2 => Self::Rice(2),
208 code_consts::RICE3 => Self::Rice(3),
209 code_consts::RICE4 => Self::Rice(4),
210 code_consts::RICE5 => Self::Rice(5),
211 code_consts::RICE6 => Self::Rice(6),
212 code_consts::RICE7 => Self::Rice(7),
213 code_consts::RICE8 => Self::Rice(8),
214 code_consts::RICE9 => Self::Rice(9),
215 code_consts::RICE10 => Self::Rice(10),
216 code_consts::PI1 => Self::Pi(1),
217 code_consts::PI2 => Self::Pi(2),
218 code_consts::PI3 => Self::Pi(3),
219 code_consts::PI4 => Self::Pi(4),
220 code_consts::PI5 => Self::Pi(5),
221 code_consts::PI6 => Self::Pi(6),
222 code_consts::PI7 => Self::Pi(7),
223 code_consts::PI8 => Self::Pi(8),
224 code_consts::PI9 => Self::Pi(9),
225 code_consts::PI10 => Self::Pi(10),
226 code_consts::GOLOMB3 => Self::Golomb(3),
227 code_consts::GOLOMB5 => Self::Golomb(5),
228 code_consts::GOLOMB6 => Self::Golomb(6),
229 code_consts::GOLOMB7 => Self::Golomb(7),
230 code_consts::GOLOMB9 => Self::Golomb(9),
231 code_consts::GOLOMB10 => Self::Golomb(10),
232 code_consts::EXP_GOLOMB1 => Self::ExpGolomb(1),
233 code_consts::EXP_GOLOMB2 => Self::ExpGolomb(2),
234 code_consts::EXP_GOLOMB3 => Self::ExpGolomb(3),
235 code_consts::EXP_GOLOMB4 => Self::ExpGolomb(4),
236 code_consts::EXP_GOLOMB5 => Self::ExpGolomb(5),
237 code_consts::EXP_GOLOMB6 => Self::ExpGolomb(6),
238 code_consts::EXP_GOLOMB7 => Self::ExpGolomb(7),
239 code_consts::EXP_GOLOMB8 => Self::ExpGolomb(8),
240 code_consts::EXP_GOLOMB9 => Self::ExpGolomb(9),
241 code_consts::EXP_GOLOMB10 => Self::ExpGolomb(10),
242 _ => return Err(DispatchError::UnsupportedCodeConst(const_code)),
243 })
244 }
245}
246
247impl DynamicCodeRead for Codes {
248 #[inline]
249 fn read<E: Endianness, CR: CodesRead<E> + ?Sized>(
250 &self,
251 reader: &mut CR,
252 ) -> Result<u64, CR::Error> {
253 Ok(match self.canonicalize() {
254 Codes::Unary => reader.read_unary()?,
255 Codes::Gamma => reader.read_gamma()?,
256 Codes::Delta => reader.read_delta()?,
257 Codes::Omega => reader.read_omega()?,
258 Codes::VByteBe => reader.read_vbyte_be()?,
259 Codes::VByteLe => reader.read_vbyte_le()?,
260 Codes::Zeta(3) => reader.read_zeta3()?,
261 Codes::Zeta(k) => reader.read_zeta(k)?,
262 Codes::Pi(2) => reader.read_pi2()?,
263 Codes::Pi(k) => reader.read_pi(k)?,
264 Codes::Golomb(b) => reader.read_golomb(b)?,
265 Codes::ExpGolomb(k) => reader.read_exp_golomb(k)?,
266 Codes::Rice(log2_b) => reader.read_rice(log2_b)?,
267 })
268 }
269}
270
271impl DynamicCodeWrite for Codes {
272 #[inline]
273 fn write<E: Endianness, CW: CodesWrite<E> + ?Sized>(
274 &self,
275 writer: &mut CW,
276 n: u64,
277 ) -> Result<usize, CW::Error> {
278 Ok(match self.canonicalize() {
279 Codes::Unary => writer.write_unary(n)?,
280 Codes::Gamma => writer.write_gamma(n)?,
281 Codes::Delta => writer.write_delta(n)?,
282 Codes::Omega => writer.write_omega(n)?,
283 Codes::VByteBe => writer.write_vbyte_be(n)?,
284 Codes::VByteLe => writer.write_vbyte_le(n)?,
285 Codes::Zeta(3) => writer.write_zeta3(n)?,
286 Codes::Zeta(k) => writer.write_zeta(n, k)?,
287 Codes::Pi(2) => writer.write_pi2(n)?,
288 Codes::Pi(k) => writer.write_pi(n, k)?,
289 Codes::Golomb(b) => writer.write_golomb(n, b)?,
290 Codes::ExpGolomb(k) => writer.write_exp_golomb(n, k)?,
291 Codes::Rice(log2_b) => writer.write_rice(n, log2_b)?,
292 })
293 }
294}
295
296impl<E: Endianness, CR: CodesRead<E> + ?Sized> StaticCodeRead<E, CR> for Codes {
297 #[inline(always)]
298 fn read(&self, reader: &mut CR) -> Result<u64, CR::Error> {
299 <Self as DynamicCodeRead>::read(self, reader)
300 }
301}
302
303impl<E: Endianness, CW: CodesWrite<E> + ?Sized> StaticCodeWrite<E, CW> for Codes {
304 #[inline(always)]
305 fn write(&self, writer: &mut CW, n: u64) -> Result<usize, CW::Error> {
306 <Self as DynamicCodeWrite>::write(self, writer, n)
307 }
308}
309
310impl CodeLen for Codes {
311 #[inline]
312 fn len(&self, n: u64) -> usize {
313 match self.canonicalize() {
314 Codes::Unary => n
316 .checked_add(1)
317 .and_then(|len| usize::try_from(len).ok())
318 .expect("unary code length does not fit in a usize"),
319 Codes::Gamma => len_gamma(n),
320 Codes::Delta => len_delta(n),
321 Codes::Omega => len_omega(n),
322 Codes::VByteLe | Codes::VByteBe => bit_len_vbyte(n),
323 Codes::Zeta(k) => len_zeta(n, k),
324 Codes::Pi(k) => len_pi(n, k),
325 Codes::Golomb(b) => len_golomb(n, b),
326 Codes::ExpGolomb(k) => len_exp_golomb(n, k),
327 Codes::Rice(log2_b) => len_rice(n, log2_b),
328 }
329 }
330}
331
332#[cfg(feature = "serde")]
333impl serde::Serialize for Codes {
334 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
335 serializer.serialize_str(&self.to_string())
336 }
337}
338
339#[cfg(feature = "serde")]
340impl<'de> serde::Deserialize<'de> for Codes {
341 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
342 let s = String::deserialize(deserializer)?;
343 s.parse().map_err(serde::de::Error::custom)
344 }
345}
346
347impl core::fmt::Display for Codes {
348 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
349 match self {
350 Codes::Unary => write!(f, "Unary"),
351 Codes::Gamma => write!(f, "Gamma"),
352 Codes::Delta => write!(f, "Delta"),
353 Codes::Omega => write!(f, "Omega"),
354 Codes::VByteBe => write!(f, "VByteBe"),
355 Codes::VByteLe => write!(f, "VByteLe"),
356 Codes::Zeta(k) => write!(f, "Zeta({})", k),
357 Codes::Pi(k) => write!(f, "Pi({})", k),
358 Codes::Golomb(b) => write!(f, "Golomb({})", b),
359 Codes::ExpGolomb(k) => write!(f, "ExpGolomb({})", k),
360 Codes::Rice(log2_b) => write!(f, "Rice({})", log2_b),
361 }
362 }
363}
364
365fn array_format_error(s: &str) -> [u8; 32] {
366 let mut error_buffer = [0u8; 32];
367 let len = s.len().min(32);
368 error_buffer[..len].copy_from_slice(&s.as_bytes()[..len]);
369 error_buffer
370}
371
372impl core::str::FromStr for Codes {
373 type Err = CodeError;
374
375 fn from_str(s: &str) -> Result<Self, Self::Err> {
376 match s {
377 "Unary" => Ok(Codes::Unary),
378 "Gamma" => Ok(Codes::Gamma),
379 "Delta" => Ok(Codes::Delta),
380 "Omega" => Ok(Codes::Omega),
381 "VByteBe" => Ok(Codes::VByteBe),
382 "VByteLe" => Ok(Codes::VByteLe),
383
384 _ => {
385 let inner = s
389 .strip_suffix(')')
390 .ok_or_else(|| CodeError::UnknownCode(array_format_error(s)))?;
391 let (name, param) = inner
392 .split_once('(')
393 .ok_or_else(|| CodeError::UnknownCode(array_format_error(s)))?;
394 if param.contains('(') || param.contains(')') {
395 return Err(CodeError::UnknownCode(array_format_error(s)));
396 }
397 let invalid = || CodeError::InvalidParameter(array_format_error(s));
398 match name {
399 "Zeta" => {
401 let k: usize = param.parse()?;
402 if k == 0 || k >= 64 {
403 return Err(invalid());
404 }
405 Ok(Codes::Zeta(k))
406 }
407 "Pi" => {
410 let k: usize = param.parse()?;
411 if k >= 64 {
412 return Err(invalid());
413 }
414 Ok(Codes::Pi(k))
415 }
416 "ExpGolomb" => {
417 let k: usize = param.parse()?;
418 if k >= 64 {
419 return Err(invalid());
420 }
421 Ok(Codes::ExpGolomb(k))
422 }
423 "Rice" => {
424 let k: usize = param.parse()?;
425 if k >= 64 {
426 return Err(invalid());
427 }
428 Ok(Codes::Rice(k))
429 }
430 "Golomb" => {
432 let b: u64 = param.parse()?;
433 if b == 0 {
434 return Err(invalid());
435 }
436 Ok(Codes::Golomb(b))
437 }
438 _ => Err(CodeError::UnknownCode(array_format_error(name))),
439 }
440 }
441 }
442 }
443}
444
445#[derive(Debug, Clone)]
447pub enum CodeError {
448 ParseError(core::num::ParseIntError),
450 UnknownCode([u8; 32]),
452 InvalidParameter([u8; 32]),
455}
456impl core::error::Error for CodeError {}
457impl core::fmt::Display for CodeError {
458 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
459 match self {
460 CodeError::ParseError(e) => write!(f, "parse error: {}", e),
461 CodeError::UnknownCode(s) => {
462 write!(f, "unknown code: ")?;
463 for c in s {
464 if *c == 0 {
465 break;
466 }
467 write!(f, "{}", *c as char)?;
468 }
469 Ok(())
470 }
471 CodeError::InvalidParameter(s) => {
472 write!(f, "invalid parameter for code: ")?;
473 for c in s {
474 if *c == 0 {
475 break;
476 }
477 write!(f, "{}", *c as char)?;
478 }
479 Ok(())
480 }
481 }
482 }
483}
484
485impl From<core::num::ParseIntError> for CodeError {
486 fn from(e: core::num::ParseIntError) -> Self {
487 CodeError::ParseError(e)
488 }
489}
490
491#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
503pub struct MinimalBinary(
504 pub u64,
506);
507
508impl DynamicCodeRead for MinimalBinary {
509 fn read<E: Endianness, R: CodesRead<E> + ?Sized>(
510 &self,
511 reader: &mut R,
512 ) -> Result<u64, R::Error> {
513 reader.read_minimal_binary(self.0)
514 }
515}
516
517impl DynamicCodeWrite for MinimalBinary {
518 fn write<E: Endianness, W: CodesWrite<E> + ?Sized>(
519 &self,
520 writer: &mut W,
521 n: u64,
522 ) -> Result<usize, W::Error> {
523 writer.write_minimal_binary(n, self.0)
524 }
525}
526
527impl<E: Endianness, CR: CodesRead<E> + ?Sized> StaticCodeRead<E, CR> for MinimalBinary {
528 fn read(&self, reader: &mut CR) -> Result<u64, CR::Error> {
529 <Self as DynamicCodeRead>::read(self, reader)
530 }
531}
532
533impl<E: Endianness, CW: CodesWrite<E> + ?Sized> StaticCodeWrite<E, CW> for MinimalBinary {
534 fn write(&self, writer: &mut CW, n: u64) -> Result<usize, CW::Error> {
535 <Self as DynamicCodeWrite>::write(self, writer, n)
536 }
537}
538
539impl CodeLen for MinimalBinary {
540 fn len(&self, n: u64) -> usize {
541 len_minimal_binary(n, self.0)
542 }
543}
544
545#[cfg(test)]
546mod parse_tests {
547 use super::Codes;
548 use core::str::FromStr;
549
550 #[test]
551 fn test_parses_valid_parameterized_codes() {
552 assert_eq!(Codes::from_str("Unary").unwrap(), Codes::Unary);
553 assert_eq!(Codes::from_str("Zeta(3)").unwrap(), Codes::Zeta(3));
554 assert_eq!(Codes::from_str("Pi(2)").unwrap(), Codes::Pi(2));
555 assert_eq!(Codes::from_str("Golomb(7)").unwrap(), Codes::Golomb(7));
556 assert_eq!(
557 Codes::from_str("ExpGolomb(0)").unwrap(),
558 Codes::ExpGolomb(0)
559 );
560 assert_eq!(Codes::from_str("Rice(0)").unwrap(), Codes::Rice(0));
561 assert_eq!(Codes::from_str("Rice(63)").unwrap(), Codes::Rice(63));
562 }
563
564 #[test]
565 fn test_rejects_out_of_range_parameters() {
566 assert!(Codes::from_str("Golomb(0)").is_err());
569 assert!(Codes::from_str("Zeta(0)").is_err());
570 assert!(Codes::from_str("Zeta(64)").is_err());
571 assert!(Codes::from_str("Rice(64)").is_err());
572 assert!(Codes::from_str("Pi(64)").is_err());
573 assert!(Codes::from_str("ExpGolomb(64)").is_err());
574 }
575
576 #[test]
577 fn test_rejects_malformed_grammar() {
578 assert!(Codes::from_str("Zeta(3").is_err());
579 assert!(Codes::from_str("Zeta(3)x").is_err());
580 assert!(Codes::from_str("Zeta(3)(4)").is_err());
581 assert!(Codes::from_str("Zeta()").is_err());
582 assert!(Codes::from_str("Nope(1)").is_err());
583 }
584}