1use core::{fmt, mem::MaybeUninit, slice, str};
8use std::{cmp::Ordering, intrinsics, io, iter::FusedIterator};
9
10use bytes::{BufMut, Bytes};
11
12use super::{error::*, fixed_arr::*, opt};
13
14pub type ETable = [u8; 256];
16pub type DTable = [u8; 256];
18
19#[derive(Clone, Copy, Debug)]
25pub struct Encoding<const N: usize> {
26 dtable: DTable,
27 etable: ETable,
28 pad: u8,
29}
30
31impl<const N: usize> Encoding<N> {
32 pub const BITS_PER_CHAR: u32 = N.trailing_zeros();
34 pub const GROUP_IN: usize = (Self::GROUP_OUT * Self::BITS_PER_CHAR as usize) / 8;
36 pub const GROUP_OUT: usize = 8 / Self::const_gcd(8, Self::BITS_PER_CHAR as usize);
38 pub const MASK: u8 = (N - 1) as u8;
40
41 const fn const_gcd(mut a: usize, mut b: usize) -> usize {
43 while b != 0 {
44 let t = a % b;
45 a = b;
46 b = t;
47 }
48 a
49 }
50
51 pub const fn new(alphabet: &[u8; N], pad: Option<u8>) -> Self {
53 assert!(N.is_power_of_two(), "base must be power of 2");
54 assert!(N <= 256, "base must be <= 256");
55
56 let mut dtable: DTable = [0xff; _];
57 let mut etable: ETable = [0; _];
58 let mut i = 0;
59 while i < N {
60 let ch = alphabet[i] as usize;
61 assert!(dtable[ch] == 0xff, "duplicate character in alphabet");
62 dtable[ch] = i as u8;
63 etable[i] = ch as u8;
64 i += 1;
65 }
66 while i < 256 {
67 etable[i] = alphabet[i % N];
68 i += 1;
69 }
70
71 let pad = if let Some(pad) = pad {
72 assert!(pad != 0, "padding char must not be 0");
73 assert!(dtable[pad as usize] == 0xff, "padding char must not be in alphabet");
74 dtable[pad as usize] = 0xfe;
76 pad
77 } else {
78 0
79 };
80
81 Self { etable, dtable, pad }
82 }
83
84 pub const fn with_lowercase(mut self) -> Self {
86 let mut c = b'A';
87 while c <= b'Z' {
88 let idx = self.dtable[c as usize];
89 if idx != 0xff {
90 self.dtable[(c | 0x20) as usize] = idx;
91 }
92 c += 1;
93 }
94 self
95 }
96
97 #[inline(always)]
99 pub const fn mask(&self) -> u8 {
100 Self::MASK
101 }
102
103 #[inline(always)]
105 pub const fn group_size_out(&self) -> usize {
106 Self::GROUP_OUT
107 }
108
109 #[inline(always)]
111 pub const fn group_size_in(&self) -> usize {
112 Self::GROUP_IN
113 }
114
115 #[inline(always)]
117 pub const fn padding(&self) -> Option<u8> {
118 if self.pad == 0 { None } else { Some(self.pad) }
119 }
120
121 #[inline(always)]
123 pub const fn bits_per_char(&self) -> u32 {
124 Self::BITS_PER_CHAR
125 }
126
127 #[inline]
129 pub const fn encode_len(&self, src_len: usize) -> usize {
130 let bits = Self::BITS_PER_CHAR as usize;
131 let chars = (src_len * 8).div_ceil(bits);
132 if self.pad == 0 {
133 chars
134 } else {
135 let group = Self::GROUP_OUT;
136 chars.div_ceil(group) * group
137 }
138 }
139
140 #[inline]
143 pub const fn decode_len(&self, chars_len_upto_pad: usize) -> usize {
144 let bits = Self::BITS_PER_CHAR as usize;
145 (chars_len_upto_pad * bits) / 8
146 }
147
148 #[inline(always)]
150 pub const fn encode(&self, value: u8) -> u8 {
151 self.etable[value as usize]
152 }
153
154 #[inline(always)]
157 pub const fn decode(&self, ch: u8) -> Option<u8> {
158 let val = self.dtable[ch as usize];
159 if val >= 0xfe {
160 std::hint::cold_path();
161 None
162 } else {
163 Some(val)
164 }
165 }
166
167 #[inline]
171 pub const fn encode_mut(&self, src: &[u8], dst: &mut [u8]) -> usize {
172 intrinsics::const_eval_select((self, src, dst), Self::encode_const, Self::encode_opt)
173 }
174
175 #[inline]
179 pub const fn decode_mut(&self, src: &[u8], dst: &mut [u8]) -> Result<usize> {
180 intrinsics::const_eval_select((self, src, dst), Self::decode_const, Self::decode_opt)
181 }
182
183 #[inline]
185 pub const fn encode_n<const L: usize>(&self, src: &[u8; L]) -> ArrayStr<L> {
186 let mut out = [[0u8; 2]; L];
187 assert!(
191 self.encode_len(L) <= (L * 2),
192 "encode_n: capacity (2*L) insufficient for this encoding"
193 );
194 let len = self.encode_mut(src, out.as_flattened_mut());
195 ArrayStr::new(out, len)
196 }
197
198 #[inline]
200 pub const fn decode_n<const L: usize>(&self, src: &[u8; L]) -> Option<Array<L>> {
201 let mut out = [0u8; L];
202 let Ok(len) = self.decode_mut(src, &mut out) else {
203 return None;
204 };
205 Some(Array::new(out, len))
206 }
207
208 #[inline]
226 pub const fn encode_writer<W: io::Write>(&self, inner: W) -> EncodeWriter<W, N> {
227 EncodeWriter::new(inner, *self)
228 }
229
230 #[inline]
251 pub const fn decode_writer<W: io::Write>(&self, inner: W) -> DecodeWriter<W, N> {
252 DecodeWriter::new(inner, *self)
253 }
254
255 #[doc(hidden)]
257 #[inline(always)]
258 pub fn encode_opt(this: &Self, src: &[u8], dst: &mut [u8]) -> usize {
259 if const { N == 64 } {
260 opt::enc64(src, &this.etable, dst, this.pad)
261 } else if const { N == 32 } {
262 opt::enc32(src, &this.etable, dst, this.pad)
263 } else {
264 Self::encode_const(this, src, dst)
265 }
266 }
267
268 #[doc(hidden)]
270 #[inline(always)]
271 pub fn decode_opt(this: &Self, src: &[u8], dst: &mut [u8]) -> Result<usize> {
272 if const { N == 64 } {
273 opt::dec64(src, &this.dtable, dst, this.pad)
274 } else if const { N == 32 } {
275 opt::dec32(src, &this.dtable, dst, this.pad)
276 } else {
277 Self::decode_const(this, src, dst)
278 }
279 }
280
281 #[doc(hidden)]
283 #[inline(always)]
284 pub const fn encode_const(this: &Self, src: &[u8], dst: &mut [u8]) -> usize {
285 let bits = Self::BITS_PER_CHAR;
286 let mask = Self::MASK;
287 let group_in = Self::GROUP_IN;
288 let group_out = Self::GROUP_OUT;
289 let pad = this.pad;
290
291 let mut src_idx = 0;
292 let mut dst_idx = 0;
293
294 while src_idx + group_in <= src.len() && dst_idx + group_out <= dst.len() {
296 let mut buffer = 0u64;
297 let mut buffer_bits = 0u32;
298
299 let mut i = 0;
300 while i < group_in {
301 buffer = (buffer << 8) | (src[src_idx] as u64);
302 buffer_bits += 8;
303 src_idx += 1;
304 i += 1;
305 }
306
307 let mut j = 0;
308 while j < group_out {
309 buffer_bits -= bits;
310 let val = ((buffer >> buffer_bits) & (mask as u64)) as u8;
311 dst[dst_idx] = this.encode(val);
312 dst_idx += 1;
313 j += 1;
314 }
315 }
316
317 if src_idx < src.len() {
319 let mut buffer = 0u64;
320 let mut buffer_bits = 0u32;
321
322 while src_idx < src.len() {
323 buffer = (buffer << 8) | (src[src_idx] as u64);
324 buffer_bits += 8;
325 src_idx += 1;
326 }
327
328 while buffer_bits >= bits && dst_idx < dst.len() {
329 buffer_bits -= bits;
330 let val = ((buffer >> buffer_bits) & (mask as u64)) as u8;
331 dst[dst_idx] = this.encode(val);
332 dst_idx += 1;
333 }
334
335 if buffer_bits > 0 && dst_idx < dst.len() {
336 let val = ((buffer << (bits - buffer_bits)) & (mask as u64)) as u8;
337 dst[dst_idx] = this.encode(val);
338 dst_idx += 1;
339 }
340
341 if pad != 0 {
343 let expected = (src.len() * 8).div_ceil(bits as usize).div_ceil(group_out) * group_out;
344 while dst_idx < expected && dst_idx < dst.len() {
345 dst[dst_idx] = pad;
346 dst_idx += 1;
347 }
348 }
349 }
350
351 dst_idx
352 }
353
354 #[doc(hidden)]
356 #[inline(always)]
357 pub const fn decode_const(this: &Self, src: &[u8], dst: &mut [u8]) -> Result<usize> {
358 let bits = Self::BITS_PER_CHAR;
359 let pad = this.pad;
360
361 let mut src_idx = 0;
362 let mut dst_idx = 0;
363 let mut buffer = 0u64;
364 let mut buffer_bits = 0u32;
365
366 while src_idx < src.len() {
367 let ch = src[src_idx];
368 src_idx += 1;
369
370 if pad != 0 && ch == pad {
371 break;
372 }
373
374 let Some(val) = this.decode(ch) else {
375 return Err(DecodeError::InvalidCharacter(ch));
376 };
377
378 buffer = (buffer << bits) | (val as u64);
379 buffer_bits += bits;
380
381 while buffer_bits >= 8 && dst_idx < dst.len() {
382 buffer_bits -= 8;
383 dst[dst_idx] = ((buffer >> buffer_bits) & 0xff) as u8;
384 dst_idx += 1;
385 }
386 }
387
388 Ok(dst_idx)
389 }
390}
391
392#[derive(Debug, Clone)]
406pub struct Decoder<'a, const N: usize> {
407 src: &'a [u8],
409 enc: &'a Encoding<N>,
411 buffer: u64,
413 buffer_bits: u8,
415 bits: u8,
417 remaining_nonpad: usize,
419}
420
421impl<'a, const N: usize> Decoder<'a, N> {
422 pub const fn new(src: &'a [u8], enc: &'a Encoding<N>) -> Self {
424 let bits = Encoding::<N>::BITS_PER_CHAR as u8;
425
426 let remaining_nonpad = if enc.pad == 0 {
428 src.len()
429 } else {
430 let mut i = 0;
431 while i < src.len() {
432 if src[i] == enc.pad {
433 break;
434 }
435 i += 1;
436 }
437 i
438 };
439
440 Self { src, enc, buffer: 0, buffer_bits: 0, bits, remaining_nonpad }
441 }
442
443 pub fn into_vec(self) -> Result<Vec<u8>> {
445 let cap = self.enc.decode_len(self.remaining_nonpad);
446 let mut buf = vec![0u8; cap];
447 let written = self.enc.decode_mut(self.src, &mut buf)?;
448 buf.truncate(written);
449 Ok(buf)
450 }
451
452 pub fn into_bytes(self) -> Result<Bytes> {
454 self.into_vec().map(Bytes::from)
455 }
456
457 #[inline]
459 pub const fn into_slice(self, buf: &mut [u8]) -> Result<usize> {
460 self.enc.decode_mut(self.src, buf)
461 }
462
463 pub fn into_array<const K: usize>(self) -> Result<[u8; K]> {
465 let mut buf = [0u8; K];
466 let n = self.into_slice(&mut buf)?;
467 if n != K {
468 return Err(DecodeError::InputTooShort);
469 }
470 Ok(buf)
471 }
472
473 pub fn into_buf<B: BufMut>(mut self, mut buf: B) -> Result<B> {
475 loop {
476 let mut n = 0;
477 let chunk = unsafe { buf.chunk_mut().as_uninit_slice_mut() };
479
480 if chunk.is_empty() {
482 break Ok(buf);
483 }
484
485 for (b, dst) in self.by_ref().zip(&mut *chunk) {
486 dst.write(b?);
487 n += 1;
488 }
489 let exhausted = n < chunk.len();
490
491 unsafe { buf.advance_mut(n) };
493
494 if exhausted {
495 break Ok(buf);
496 }
497 }
498 }
499
500 pub fn extend_into<E: Extend<u8> + ?Sized>(self, buf: &mut E) -> Result<usize> {
502 let mut n = 0;
503 for byte in self {
504 buf.extend_one(byte?);
505 n += 1;
506 }
507 Ok(n)
508 }
509
510 pub fn write_into<W: io::Write + ?Sized>(mut self, writer: &mut W) -> io::Result<usize> {
512 let mut tmp = [MaybeUninit::<u8>::uninit(); 512];
513 let mut total = 0;
514 loop {
515 let mut i = 0;
516 for dst in &mut tmp {
517 if let Some(b) = self.next() {
518 dst.write(b.map_err(io::Error::other)?);
519 i += 1;
520 } else {
521 break;
522 }
523 }
524 if i == 0 {
525 break;
526 }
527 unsafe {
531 writer.write_all(slice::from_raw_parts(tmp.as_ptr().cast(), i))?;
532 }
533 total += i;
534 }
535 Ok(total)
536 }
537}
538
539impl<const N: usize> Iterator for Decoder<'_, N> {
540 type Item = Result<u8>;
541
542 fn next(&mut self) -> Option<Self::Item> {
543 let bits = self.bits;
544
545 loop {
546 if self.buffer_bits >= 8 {
548 let shift = self.buffer_bits - 8;
549 let byte = ((self.buffer >> shift) & 0xff) as u8;
550 self.buffer_bits -= 8;
551 return Some(Ok(byte));
553 }
554
555 let ch = *self.src.split_off_first()?;
557
558 if self.enc.pad != 0 && ch == self.enc.pad {
560 return None;
561 }
562
563 let Some(val) = self.enc.decode(ch) else {
565 return Some(Err(DecodeError::InvalidCharacter(ch)));
566 };
567
568 self.remaining_nonpad = self.remaining_nonpad.saturating_sub(1);
570
571 self.buffer = (self.buffer << bits) | (val as u64);
573 self.buffer_bits += bits;
574 }
575 }
576
577 fn size_hint(&self) -> (usize, Option<usize>) {
578 let n = self.len();
579 (n, Some(n))
580 }
581}
582
583impl<const N: usize> ExactSizeIterator for Decoder<'_, N> {
584 #[inline]
585 fn len(&self) -> usize {
586 let bits = self.bits as usize;
588 ((self.remaining_nonpad * bits) + self.buffer_bits as usize) / 8
589 }
590}
591
592impl<const N: usize> FusedIterator for Decoder<'_, N> {}
593
594impl<const N: usize, const K: usize> TryFrom<Decoder<'_, N>> for [u8; K] {
595 type Error = DecodeError;
596
597 fn try_from(decoder: Decoder<'_, N>) -> Result<Self> {
598 decoder.into_array()
599 }
600}
601
602impl<const N: usize> fmt::Display for Decoder<'_, N> {
603 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
604 for byte in self.clone() {
605 if let Ok(byte) = byte {
606 write!(f, "{byte:02x}")?;
607 } else {
608 write!(f, "??")?;
609 }
610 }
611 Ok(())
612 }
613}
614
615impl<const N: usize> PartialEq<[u8]> for Decoder<'_, N> {
616 fn eq(&self, other: &[u8]) -> bool {
617 self.clone().eq(other.iter().map(|&b| Ok(b)))
618 }
619}
620
621impl<const N: usize> PartialOrd<[u8]> for Decoder<'_, N> {
622 fn partial_cmp(&self, other: &[u8]) -> Option<Ordering> {
623 Some(self.clone().cmp(other.iter().map(|&b| Ok(b))))
624 }
625}
626
627#[derive(Debug, Clone)]
641pub struct Encoder<'a, const N: usize> {
642 src: &'a [u8],
644 enc: &'a Encoding<N>,
646 buffer: u64,
648 buffer_bits: usize,
650 chars_emitted: usize,
652 padding_count: usize,
654 done: bool,
656}
657
658impl<'a, const N: usize> Encoder<'a, N> {
659 pub const fn new(src: &'a [u8], enc: &'a Encoding<N>) -> Self {
661 Self { src, enc, buffer: 0, buffer_bits: 0, chars_emitted: 0, padding_count: 0, done: false }
662 }
663
664 pub fn into_vec(self) -> Vec<u8> {
666 let out_len = self.enc.encode_len(self.src.len());
667 let mut buf = vec![0u8; out_len];
668 let written = self.enc.encode_mut(self.src, &mut buf);
669 buf.truncate(written);
670 buf
671 }
672
673 pub fn into_bytes(self) -> Bytes {
675 Bytes::from(self.into_vec())
676 }
677
678 pub fn into_string(self) -> String {
680 ascii_to_str_owned(self.into_vec())
681 }
682
683 pub fn extend_into<E: Extend<u8> + ?Sized>(self, buf: &mut E) {
685 buf.extend(self);
686 }
687
688 pub fn into_buf<B: BufMut>(mut self, mut buf: B) -> B {
690 loop {
691 let mut n = 0;
692 let chunk = unsafe { buf.chunk_mut().as_uninit_slice_mut() };
694
695 if chunk.is_empty() {
697 break buf;
698 }
699
700 for (b, dst) in self.by_ref().zip(&mut *chunk) {
701 dst.write(b);
702 n += 1;
703 }
704 let exhausted = n < chunk.len();
705 unsafe { buf.advance_mut(n) };
707 if exhausted {
708 break buf;
709 }
710 }
711 }
712
713 pub fn write_into<W: io::Write + ?Sized>(mut self, writer: &mut W) -> io::Result<usize> {
715 let mut tmp = [MaybeUninit::<u8>::uninit(); 512];
716 let mut total = 0;
717 loop {
718 let mut i = 0;
719 for dst in &mut tmp {
720 if let Some(b) = self.next() {
721 dst.write(b);
722 i += 1;
723 } else {
724 break;
725 }
726 }
727 if i == 0 {
728 break;
729 }
730 unsafe {
734 writer.write_all(slice::from_raw_parts(tmp.as_ptr().cast(), i))?;
735 }
736 total += i;
737 }
738 Ok(total)
739 }
740
741 pub fn format_into<W: fmt::Write + ?Sized>(self, writer: &mut W) -> fmt::Result {
743 for byte in self {
744 writer.write_char(byte as char)?;
745 }
746 Ok(())
747 }
748}
749
750impl<const N: usize> From<Encoder<'_, N>> for String {
751 fn from(encoder: Encoder<'_, N>) -> Self {
752 encoder.into_string()
753 }
754}
755
756impl<const N: usize> From<Encoder<'_, N>> for Bytes {
757 fn from(encoder: Encoder<'_, N>) -> Self {
758 encoder.into_bytes()
759 }
760}
761
762impl<const N: usize> From<Encoder<'_, N>> for Vec<u8> {
763 fn from(encoder: Encoder<'_, N>) -> Self {
764 encoder.into_vec()
765 }
766}
767
768impl<const N: usize> Iterator for Encoder<'_, N> {
769 type Item = u8;
770
771 fn next(&mut self) -> Option<Self::Item> {
772 let bits = Encoding::<N>::BITS_PER_CHAR as usize;
773 let mask = Encoding::<N>::MASK;
774
775 loop {
776 if self.padding_count > 0 {
778 self.padding_count -= 1;
779 return self.enc.padding();
780 }
781
782 if self.buffer_bits >= bits {
784 let shift = self.buffer_bits - bits;
785 let val = ((self.buffer >> shift) as u8) & mask;
786 self.buffer_bits -= bits;
787 self.chars_emitted += 1;
788 return Some(self.enc.encode(val));
789 }
790
791 if let Some(byte) = self.src.split_off_first() {
793 self.buffer = (self.buffer << 8) | (*byte as u64);
794 self.buffer_bits += 8;
795 continue;
796 }
797
798 if !self.done {
800 self.done = true;
801
802 if self.buffer_bits > 0 {
804 let val = ((self.buffer << (bits - self.buffer_bits)) as u8) & mask;
805 self.buffer_bits = 0;
806 let total_chars = self.chars_emitted + 1;
807
808 if self.enc.pad != 0 {
809 let group_out = Encoding::<N>::GROUP_OUT;
810 let rem = total_chars % group_out;
811 if rem > 0 {
812 self.padding_count = group_out - rem;
813 }
814 }
815
816 self.chars_emitted += 1;
817 return Some(self.enc.encode(val));
818 }
819
820 if self.enc.pad != 0 && self.chars_emitted > 0 {
822 let group_out = Encoding::<N>::GROUP_OUT;
823 let rem = self.chars_emitted % group_out;
824 if rem > 0 {
825 self.padding_count = group_out - rem;
826 continue;
827 }
828 }
829 }
830
831 return None;
832 }
833 }
834
835 fn size_hint(&self) -> (usize, Option<usize>) {
836 let n = self.len();
837 (n, Some(n))
838 }
839}
840
841impl<const N: usize> ExactSizeIterator for Encoder<'_, N> {
842 #[inline]
843 fn len(&self) -> usize {
844 let bits = Encoding::<N>::BITS_PER_CHAR as usize;
845 let total_bits = (self.src.len() * 8) + self.buffer_bits;
846 let chars = total_bits.div_ceil(bits) + self.padding_count;
847 if self.enc.pad != 0 {
848 let group = Encoding::<N>::GROUP_OUT;
849 chars.div_ceil(group) * group
850 } else {
851 chars
852 }
853 }
854}
855
856impl<const N: usize> FusedIterator for Encoder<'_, N> {}
857
858impl<const N: usize> serde::Serialize for Encoder<'_, N> {
859 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
860 let len = self.enc.encode_len(self.src.len());
861 serialize(serializer, len, |buffer| self.enc.encode_mut(self.src, buffer))
862 }
863}
864
865impl<const N: usize> fmt::Display for Encoder<'_, N> {
866 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
867 format_with_precision(self.clone(), f)
868 }
869}
870
871impl<const N: usize> Eq for Encoder<'_, N> {}
872
873impl<'b, const N: usize, const M: usize> PartialEq<Encoder<'b, M>> for Encoder<'_, N> {
874 fn eq(&self, other: &Encoder<'b, M>) -> bool {
875 self.clone().eq(other.clone())
876 }
877}
878impl<const N: usize> Ord for Encoder<'_, N> {
879 fn cmp(&self, other: &Self) -> Ordering {
880 self.clone().cmp(other.clone())
881 }
882}
883impl<'b, const N: usize, const M: usize> PartialOrd<Encoder<'b, M>> for Encoder<'_, N> {
884 fn partial_cmp(&self, other: &Encoder<'b, M>) -> Option<Ordering> {
885 Some(self.clone().cmp(other.clone()))
886 }
887}
888
889impl<const N: usize> PartialEq<[u8]> for Encoder<'_, N> {
890 fn eq(&self, other: &[u8]) -> bool {
891 self.clone().eq(other.iter().copied())
892 }
893}
894
895impl<const N: usize> PartialEq<str> for Encoder<'_, N> {
896 fn eq(&self, other: &str) -> bool {
897 self.clone().eq(other.as_bytes().iter().copied())
898 }
899}
900
901impl<const N: usize> PartialOrd<[u8]> for Encoder<'_, N> {
902 fn partial_cmp(&self, other: &[u8]) -> Option<Ordering> {
903 Some(self.clone().cmp(other.iter().copied()))
904 }
905}
906
907impl<const N: usize> PartialOrd<str> for Encoder<'_, N> {
908 fn partial_cmp(&self, other: &str) -> Option<Ordering> {
909 Some(self.clone().cmp(other.as_bytes().iter().copied()))
910 }
911}
912
913const INPUT_BUFFER_SIZE: usize = 768;
920const OUTPUT_BUFFER_SIZE: usize = 2048;
923
924pub struct EncodeWriter<W: io::Write, const N: usize> {
944 inner: Option<W>,
945 enc: Encoding<N>,
946 input_buf: [MaybeUninit<u8>; INPUT_BUFFER_SIZE],
947 input_len: usize,
948 output_buf: [u8; OUTPUT_BUFFER_SIZE],
949}
950
951impl<W: io::Write, const N: usize> EncodeWriter<W, N> {
952 pub const fn new(inner: W, enc: Encoding<N>) -> Self {
954 Self {
955 inner: Some(inner),
956 enc,
957 input_buf: [MaybeUninit::uninit(); INPUT_BUFFER_SIZE],
958 input_len: 0,
959 output_buf: [0u8; OUTPUT_BUFFER_SIZE],
960 }
961 }
962
963 pub fn into_inner(mut self) -> io::Result<W> {
969 io::Write::flush(&mut self)?;
970 let inner = self.inner.take().expect("EncodeWriter already consumed");
971 core::mem::forget(self);
973 Ok(inner)
974 }
975
976 fn flush_input(&mut self) -> io::Result<()> {
978 if self.input_len == 0 {
979 return Ok(());
980 }
981
982 let input_slice =
987 unsafe { slice::from_raw_parts(self.input_buf.as_ptr().cast::<u8>(), self.input_len) };
988
989 let encoded_len = self.enc.encode_mut(input_slice, &mut self.output_buf);
990 let encoded_data = &self.output_buf[..encoded_len];
991
992 let inner = self.inner.as_mut().expect("EncodeWriter inner is None");
994 inner.write_all(encoded_data)?;
995
996 self.input_len = 0;
998 Ok(())
999 }
1000}
1001
1002impl<W: io::Write, const N: usize> io::Write for EncodeWriter<W, N> {
1003 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1004 let mut bytes_written = 0;
1005
1006 while bytes_written < buf.len() {
1007 let available = INPUT_BUFFER_SIZE - self.input_len;
1008 if available == 0 {
1009 self.flush_input()?;
1010 continue;
1011 }
1012
1013 let to_copy = (buf.len() - bytes_written).min(available);
1014
1015 unsafe {
1021 let dst = self.input_buf.as_mut_ptr().add(self.input_len).cast::<u8>();
1022 let src = buf.as_ptr().add(bytes_written);
1023 core::ptr::copy_nonoverlapping(src, dst, to_copy);
1024 }
1025
1026 self.input_len += to_copy;
1027 bytes_written += to_copy;
1028 }
1029
1030 Ok(bytes_written)
1031 }
1032
1033 fn flush(&mut self) -> io::Result<()> {
1034 self.flush_input()?;
1035 self
1036 .inner
1037 .as_mut()
1038 .expect("EncodeWriter inner is None")
1039 .flush()
1040 }
1041}
1042
1043impl<W: io::Write, const N: usize> Drop for EncodeWriter<W, N> {
1044 fn drop(&mut self) {
1045 let _ = io::Write::flush(self);
1046 }
1047}
1048
1049pub struct DecodeWriter<W: io::Write, const N: usize> {
1074 inner: Option<W>,
1075 enc: Encoding<N>,
1076 input_buf: [MaybeUninit<u8>; INPUT_BUFFER_SIZE],
1077 input_len: usize,
1078 output_buf: [u8; OUTPUT_BUFFER_SIZE],
1079}
1080
1081impl<W: io::Write, const N: usize> DecodeWriter<W, N> {
1082 pub const fn new(inner: W, enc: Encoding<N>) -> Self {
1084 Self {
1085 inner: Some(inner),
1086 enc,
1087 input_buf: [MaybeUninit::uninit(); INPUT_BUFFER_SIZE],
1088 input_len: 0,
1089 output_buf: [0u8; OUTPUT_BUFFER_SIZE],
1090 }
1091 }
1092
1093 pub fn into_inner(mut self) -> io::Result<W> {
1099 io::Write::flush(&mut self)?;
1100 let inner = self.inner.take().expect("DecodeWriter already consumed");
1101 core::mem::forget(self);
1103 Ok(inner)
1104 }
1105
1106 fn flush_input(&mut self, final_flush: bool) -> io::Result<()> {
1112 if self.input_len == 0 {
1113 return Ok(());
1114 }
1115
1116 let group_out = self.enc.group_size_out();
1117
1118 let to_decode = if final_flush {
1120 self.input_len
1122 } else {
1123 (self.input_len / group_out) * group_out
1125 };
1126
1127 if to_decode == 0 {
1128 return Ok(());
1129 }
1130
1131 let input_slice =
1136 unsafe { slice::from_raw_parts(self.input_buf.as_ptr().cast::<u8>(), to_decode) };
1137
1138 let decoded_len = self
1139 .enc
1140 .decode_mut(input_slice, &mut self.output_buf)
1141 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
1142 let decoded_data = &self.output_buf[..decoded_len];
1143
1144 let inner = self.inner.as_mut().expect("DecodeWriter inner is None");
1146 inner.write_all(decoded_data)?;
1147
1148 let remaining = self.input_len - to_decode;
1150 if remaining > 0 {
1151 unsafe {
1156 core::ptr::copy(
1157 self.input_buf.as_ptr().add(to_decode),
1158 self.input_buf.as_mut_ptr(),
1159 remaining,
1160 );
1161 }
1162 }
1163 self.input_len = remaining;
1164
1165 Ok(())
1166 }
1167}
1168
1169impl<W: io::Write, const N: usize> io::Write for DecodeWriter<W, N> {
1170 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1171 let mut bytes_written = 0;
1172
1173 while bytes_written < buf.len() {
1174 let available = INPUT_BUFFER_SIZE - self.input_len;
1175 if available == 0 {
1176 self.flush_input(false)?;
1177 continue;
1178 }
1179
1180 let to_copy = (buf.len() - bytes_written).min(available);
1181
1182 unsafe {
1188 let dst = self.input_buf.as_mut_ptr().add(self.input_len).cast::<u8>();
1189 let src = buf.as_ptr().add(bytes_written);
1190 core::ptr::copy_nonoverlapping(src, dst, to_copy);
1191 }
1192
1193 self.input_len += to_copy;
1194 bytes_written += to_copy;
1195 }
1196
1197 Ok(bytes_written)
1198 }
1199
1200 fn flush(&mut self) -> io::Result<()> {
1201 self.flush_input(true)?;
1202 self
1203 .inner
1204 .as_mut()
1205 .expect("DecodeWriter inner is None")
1206 .flush()
1207 }
1208}
1209
1210impl<W: io::Write, const N: usize> Drop for DecodeWriter<W, N> {
1211 fn drop(&mut self) {
1212 let _ = io::Write::flush(self);
1213 }
1214}
1215
1216macro_rules! define_encoding {
1222 ($mod_name:ident, $n:literal, $pad:literal, $alphabet:expr, $lowercase:literal) => {
1223 #[doc = concat!(
1224 stringify!($mod_name), " encoding and decoding.\n\n",
1225 "This module provides ", stringify!($mod_name), " encoding/decoding using a ",
1226 stringify!($n), "-character alphabet. Both padded and unpadded variants are available.\n\n",
1227 )]
1228 pub mod $mod_name {
1229 use super::*;
1230
1231 #[doc = concat!(
1232 "Encoding dictionary for ", stringify!($mod_name), ".\n\n",
1233 "Defines the ", stringify!($n), "-character alphabet, padding character, and ",
1234 "encoding/decoding behavior. Use [`STD`] or [`RAW`] for standard configurations."
1235 )]
1236 pub type Encoding = super::Encoding<$n>;
1237
1238 #[doc = concat!(
1239 "Streaming decoder for ", stringify!($mod_name), "-encoded data.\n\n",
1240 "Decodes ", stringify!($mod_name), " characters into bytes. ",
1241 "Create with [`decode()`] or use [`STD`]/[`RAW`] decoder methods."
1242 )]
1243 pub type Decoder<'a> = super::Decoder<'a, $n>;
1244
1245 #[doc = concat!(
1246 "Streaming encoder for ", stringify!($mod_name), " encoding.\n\n",
1247 "Encodes bytes into ", stringify!($mod_name), " characters. ",
1248 "Create with [`encode()`] or use [`STD`]/[`RAW`] encoder methods."
1249 )]
1250 pub type Encoder<'a> = super::Encoder<'a, $n>;
1251
1252 #[doc = concat!(
1253 "Standard ", stringify!($mod_name), " encoding with padding.\n\n",
1254 "Uses a ", stringify!($n), "-character alphabet with `=` padding."
1255 )]
1256 pub const STD: Encoding = {
1257 let enc = Encoding::new($alphabet, Some($pad));
1258 #[allow(unused_mut, reason = "conditional mutation in const context for lowercase flag")]
1259 let mut enc = enc;
1260 if $lowercase {
1261 enc.with_lowercase()
1262 } else {
1263 enc
1264 }
1265 };
1266
1267 #[doc = concat!("Padded ", stringify!($mod_name), " encoding (alias of STD).")]
1268 pub const PADDED: Encoding = STD;
1269
1270 #[doc = concat!(
1271 "Raw ", stringify!($mod_name), " encoding without padding.\n\n",
1272 "Uses a ", stringify!($n), "-character alphabet with no padding characters."
1273 )]
1274 pub const RAW: Encoding = {
1275 let enc = Encoding::new($alphabet, None);
1276 #[allow(unused_mut, reason = "conditional mutation in const context for lowercase flag")]
1277 let mut enc = enc;
1278 if $lowercase {
1279 enc.with_lowercase()
1280 } else {
1281 enc
1282 }
1283 };
1284
1285 #[doc = concat!(
1286 "Encodes a byte slice to ", stringify!($mod_name), " with padding.\n\n",
1287 "# Arguments\n\n",
1288 "* `src` - The byte slice to encode\n\n",
1289 "# Returns\n\n",
1290 "An iterator that yields encoded bytes.\n\n",
1291 "# Example\n\n",
1292 "```\n",
1293 "use omp_core::", stringify!($mod_name), ";\n",
1294 "let encoded = ", stringify!($mod_name), "::encode(b\"hello\").into_string();\n",
1295 "```"
1296 )]
1297 pub fn encode<S: AsRef<[u8]> + ?Sized>(src: &S) -> Encoder {
1298 Encoder::new(src.as_ref(), &STD)
1299 }
1300
1301 #[doc = concat!(
1302 "Decodes ", stringify!($mod_name), " encoded bytes with padding.\n\n",
1303 "# Arguments\n\n",
1304 "* `src` - The encoded byte slice to decode\n\n",
1305 "# Returns\n\n",
1306 "An iterator that yields decoded bytes.\n\n",
1307 "# Example\n\n",
1308 "```\n",
1309 "use omp_core::", stringify!($mod_name), ";\n",
1310 "let encoded = ", stringify!($mod_name), "::encode(b\"hello\").into_string();\n",
1311 "let decoded = ", stringify!($mod_name), "::decode(&encoded).into_vec().unwrap();\n",
1312 "assert_eq!(decoded, b\"hello\");\n",
1313 "```"
1314 )]
1315 pub fn decode<S: AsRef<[u8]> + ?Sized>(src: &S) -> Decoder {
1316 Decoder::new(src.as_ref(), &STD)
1317 }
1318
1319 #[doc = concat!(
1320 "Encodes a fixed-size byte array to ", stringify!($mod_name), " with padding.\n\n",
1321 "# Arguments\n\n",
1322 "* `src` - The byte array to encode\n\n",
1323 "# Returns\n\n",
1324 "An `ArrayStr` containing the encoded output.\n\n",
1325 "# Example\n\n",
1326 "```\n",
1327 "use omp_core::", stringify!($mod_name), ";\n",
1328 "let data = [0x48u8, 0x65, 0x6c, 0x6c, 0x6f];\n",
1329 "let encoded = ", stringify!($mod_name), "::encode_n(&data);\n",
1330 "```"
1331 )]
1332 pub const fn encode_n<const N: usize>(src: &[u8; N]) -> ArrayStr<N> {
1333 STD.encode_n(src)
1334 }
1335
1336 #[doc = concat!(
1337 "Decodes a fixed-size ", stringify!($mod_name), " array with padding.\n\n",
1338 "# Arguments\n\n",
1339 "* `src` - The encoded byte array to decode\n\n",
1340 "# Returns\n\n",
1341 "A `Result` containing the decoded byte array or an error.\n\n",
1342 "# Example\n\n",
1343 "```\n",
1344 "use omp_core::", stringify!($mod_name), ";\n",
1345 "let data = [0x48u8, 0x65, 0x6c, 0x6c, 0x6f];\n",
1346 "let encoded = ", stringify!($mod_name), "::encode(&data).into_vec();\n",
1347 "let decoded = ", stringify!($mod_name), "::decode(&encoded).into_vec().unwrap();\n",
1348 "assert_eq!(&decoded, &data);\n",
1349 "```"
1350 )]
1351 pub const fn decode_n<const N: usize>(src: &[u8; N]) -> Option<Array<N>> {
1352 STD.decode_n(src)
1353 }
1354
1355 #[doc = concat!(
1356 "Encodes a byte slice to ", stringify!($mod_name), " without padding.\n\n",
1357 "# Arguments\n\n",
1358 "* `src` - The byte slice to encode\n\n",
1359 "# Returns\n\n",
1360 "An iterator that yields encoded bytes without padding characters.\n\n",
1361 "# Example\n\n",
1362 "```\n",
1363 "use omp_core::", stringify!($mod_name), ";\n",
1364 "let encoded = ", stringify!($mod_name), "::encode_raw(b\"hello\").into_string();\n",
1365 "```"
1366 )]
1367 pub fn encode_raw<S: AsRef<[u8]> + ?Sized>(src: &S) -> Encoder {
1368 Encoder::new(src.as_ref(), &RAW)
1369 }
1370
1371 #[doc = concat!(
1372 "Decodes ", stringify!($mod_name), " encoded bytes without padding.\n\n",
1373 "# Arguments\n\n",
1374 "* `src` - The encoded byte slice to decode\n\n",
1375 "# Returns\n\n",
1376 "An iterator that yields decoded bytes.\n\n",
1377 "# Example\n\n",
1378 "```\n",
1379 "use omp_core::", stringify!($mod_name), ";\n",
1380 "let encoded = ", stringify!($mod_name), "::encode_raw(b\"hello\").into_string();\n",
1381 "let decoded = ", stringify!($mod_name), "::decode_raw(&encoded).into_vec().unwrap();\n",
1382 "assert_eq!(decoded, b\"hello\");\n",
1383 "```"
1384 )]
1385 pub fn decode_raw<S: AsRef<[u8]> + ?Sized>(src: &S) -> Decoder {
1386 Decoder::new(src.as_ref(), &RAW)
1387 }
1388
1389 #[doc = concat!(
1390 "Encodes a fixed-size byte array to ", stringify!($mod_name), " without padding.\n\n",
1391 "# Arguments\n\n",
1392 "* `src` - The byte array to encode\n\n",
1393 "# Returns\n\n",
1394 "An `ArrayStr` containing the encoded output without padding.\n\n",
1395 "# Example\n\n",
1396 "```\n",
1397 "use omp_core::", stringify!($mod_name), ";\n",
1398 "let data = [0x48u8, 0x65, 0x6c, 0x6c, 0x6f];\n",
1399 "let encoded = ", stringify!($mod_name), "::encode_raw_n(&data);\n",
1400 "```"
1401 )]
1402 pub const fn encode_raw_n<const N: usize>(src: &[u8; N]) -> ArrayStr<N> {
1403 RAW.encode_n(src)
1404 }
1405
1406 #[doc = concat!(
1407 "Decodes a fixed-size ", stringify!($mod_name), " array without padding.\n\n",
1408 "# Arguments\n\n",
1409 "* `src` - The encoded byte array to decode\n\n",
1410 "# Returns\n\n",
1411 "A `Result` containing the decoded byte array or an error.\n\n",
1412 "# Example\n\n",
1413 "```\n",
1414 "use omp_core::", stringify!($mod_name), ";\n",
1415 "let data = [0x48u8, 0x65, 0x6c, 0x6c, 0x6f];\n",
1416 "let encoded = ", stringify!($mod_name), "::encode_raw(&data).into_vec();\n",
1417 "let decoded = ", stringify!($mod_name), "::decode_raw(&encoded).into_vec().unwrap();\n",
1418 "assert_eq!(&decoded, &data);\n",
1419 "```"
1420 )]
1421 pub const fn decode_raw_n<const N: usize>(src: &[u8; N]) -> Option<Array<N>> {
1422 RAW.decode_n(src)
1423 }
1424
1425 #[doc = concat!(
1426 "Encodes bytes into a mutable buffer with padding.\n\n",
1427 "# Arguments\n\n",
1428 "* `src` - The byte slice to encode\n",
1429 "* `dst` - The mutable buffer to write encoded characters to\n\n",
1430 "# Returns\n\n",
1431 "The number of characters written to `dst`.\n\n",
1432 "# Example\n\n",
1433 "```\n",
1434 "use omp_core::", stringify!($mod_name), ";\n",
1435 "let mut buf = [0u8; 16];\n",
1436 "let n = ", stringify!($mod_name), "::encode_mut(b\"hello\", &mut buf);\n",
1437 "```"
1438 )]
1439 pub const fn encode_mut(src: &[u8], dst: &mut [u8]) -> usize {
1440 STD.encode_mut(src, dst)
1441 }
1442
1443 #[doc = concat!(
1444 "Decodes ", stringify!($mod_name), " encoded bytes into a mutable buffer with padding.\n\n",
1445 "# Arguments\n\n",
1446 "* `src` - The encoded byte slice to decode\n",
1447 "* `dst` - The mutable buffer to write decoded bytes to\n\n",
1448 "# Returns\n\n",
1449 "The number of bytes written to `dst`, or an error if decoding failed.\n\n",
1450 "# Example\n\n",
1451 "```\n",
1452 "use omp_core::", stringify!($mod_name), ";\n",
1453 "let mut buf = [0u8; 10];\n",
1454 "let encoded = ", stringify!($mod_name), "::encode(b\"hello\").into_vec();\n",
1455 "let n = ", stringify!($mod_name), "::decode_mut(&encoded, &mut buf).unwrap();\n",
1456 "```"
1457 )]
1458 pub const fn decode_mut(src: &[u8], dst: &mut [u8]) -> Result<usize> {
1459 STD.decode_mut(src, dst)
1460 }
1461
1462 #[doc = concat!(
1463 "Encodes bytes into a mutable buffer without padding.\n\n",
1464 "# Arguments\n\n",
1465 "* `src` - The byte slice to encode\n",
1466 "* `dst` - The mutable buffer to write encoded characters to\n\n",
1467 "# Returns\n\n",
1468 "The number of characters written to `dst`.\n\n",
1469 "# Example\n\n",
1470 "```\n",
1471 "use omp_core::", stringify!($mod_name), ";\n",
1472 "let mut buf = [0u8; 16];\n",
1473 "let n = ", stringify!($mod_name), "::encode_raw_mut(b\"hello\", &mut buf);\n",
1474 "```"
1475 )]
1476 pub const fn encode_raw_mut(src: &[u8], dst: &mut [u8]) -> usize {
1477 RAW.encode_mut(src, dst)
1478 }
1479
1480 #[doc = concat!(
1481 "Decodes ", stringify!($mod_name), " encoded bytes into a mutable buffer without padding.\n\n",
1482 "# Arguments\n\n",
1483 "* `src` - The encoded byte slice to decode\n",
1484 "* `dst` - The mutable buffer to write decoded bytes to\n\n",
1485 "# Returns\n\n",
1486 "The number of bytes written to `dst`, or an error if decoding failed.\n\n",
1487 "# Example\n\n",
1488 "```\n",
1489 "use omp_core::", stringify!($mod_name), ";\n",
1490 "let mut buf = [0u8; 10];\n",
1491 "let encoded = ", stringify!($mod_name), "::encode_raw(b\"hello\").into_vec();\n",
1492 "let n = ", stringify!($mod_name), "::decode_raw_mut(&encoded, &mut buf).unwrap();\n",
1493 "```"
1494 )]
1495 pub const fn decode_raw_mut(src: &[u8], dst: &mut [u8]) -> Result<usize> {
1496 RAW.decode_mut(src, dst)
1497 }
1498
1499 #[doc = concat!(
1500 "Returns the encoded length including padding.\n\n",
1501 "Calculates how many ", stringify!($mod_name), " characters (including padding) ",
1502 "are needed to encode `src_len` bytes.\n\n",
1503 "# Arguments\n\n",
1504 "* `src_len` - Number of source bytes\n\n",
1505 "# Returns\n\n",
1506 "Number of ", stringify!($mod_name), " characters in padded output\n\n",
1507 "# Example\n\n",
1508 "```\n",
1509 "use omp_core::", stringify!($mod_name), ";\n",
1510 "// 5 bytes encodes to a specific character count\n",
1511 "let output_len = ", stringify!($mod_name), "::encode_len(5);\n",
1512 "let encoded = ", stringify!($mod_name), "::encode(&[0u8; 5]).into_vec();\n",
1513 "assert_eq!(encoded.len(), output_len);\n",
1514 "```"
1515 )]
1516 #[inline]
1517 pub const fn encode_len(src_len: usize) -> usize {
1518 STD.encode_len(src_len)
1519 }
1520
1521 #[doc = concat!(
1522 "Returns the decoded output length for padded input.\n\n",
1523 "Given the number of non-padding ", stringify!($mod_name), " characters, ",
1524 "calculates how many bytes will result from decoding.\n\n",
1525 "# Arguments\n\n",
1526 "* `src_len` - Number of encoded characters (padding characters not counted)\n\n",
1527 "# Returns\n\n",
1528 "Number of decoded bytes\n\n",
1529 "# Example\n\n",
1530 "```\n",
1531 "use omp_core::", stringify!($mod_name), ";\n",
1532 "// Encoding 5 bytes produces some chars; decoding those chars yields 5 bytes\n",
1533 "let data = [0u8; 5];\n",
1534 "let encoded = ", stringify!($mod_name), "::encode(&data).into_vec();\n",
1535 "let non_padding_len = encoded.iter().position(|&b| b == b'=').unwrap_or(encoded.len());\n",
1536 "assert_eq!(", stringify!($mod_name), "::decode_len(non_padding_len), 5);\n",
1537 "```"
1538 )]
1539 #[inline]
1540 pub const fn decode_len(src_len: usize) -> usize {
1541 STD.decode_len(src_len)
1542 }
1543
1544 #[doc = concat!(
1545 "Returns the encoded length without padding.\n\n",
1546 "Calculates how many ", stringify!($mod_name), " characters (no padding) ",
1547 "are needed to encode `src_len` bytes.\n\n",
1548 "# Arguments\n\n",
1549 "* `src_len` - Number of source bytes\n\n",
1550 "# Returns\n\n",
1551 "Number of ", stringify!($mod_name), " characters in unpadded output\n\n",
1552 "# Example\n\n",
1553 "```\n",
1554 "use omp_core::", stringify!($mod_name), ";\n",
1555 "// 5 bytes encodes to a specific character count (no padding)\n",
1556 "let output_len = ", stringify!($mod_name), "::encode_raw_len(5);\n",
1557 "let encoded = ", stringify!($mod_name), "::encode_raw(&[0u8; 5]).into_vec();\n",
1558 "assert_eq!(encoded.len(), output_len);\n",
1559 "```"
1560 )]
1561 #[inline]
1562 pub const fn encode_raw_len(src_len: usize) -> usize {
1563 RAW.encode_len(src_len)
1564 }
1565
1566 #[doc = concat!(
1567 "Returns the decoded output length for unpadded input.\n\n",
1568 "Given the number of ", stringify!($mod_name), " characters (no padding), ",
1569 "calculates how many bytes will result from decoding.\n\n",
1570 "# Arguments\n\n",
1571 "* `src_len` - Number of unpadded encoded characters\n\n",
1572 "# Returns\n\n",
1573 "Number of decoded bytes\n\n",
1574 "# Example\n\n",
1575 "```\n",
1576 "use omp_core::", stringify!($mod_name), ";\n",
1577 "// Encoding 5 bytes without padding produces chars; decoding yields 5 bytes\n",
1578 "let data = [0u8; 5];\n",
1579 "let encoded = ", stringify!($mod_name), "::encode_raw(&data).into_vec();\n",
1580 "assert_eq!(", stringify!($mod_name), "::decode_raw_len(encoded.len()), 5);\n",
1581 "```"
1582 )]
1583 #[inline]
1584 pub const fn decode_raw_len(src_len: usize) -> usize {
1585 RAW.decode_len(src_len)
1586 }
1587
1588 #[doc = concat!(
1589 "Creates an encoding writer that wraps an `io::Write`.\\n\\n",
1590 "The writer buffers raw bytes, encodes them to ", stringify!($mod_name), " with padding, ",
1591 "and writes the encoded output to the inner writer.\\n\\n",
1592 "# Examples\\n\\n",
1593 "```\\n",
1594 "use omp_core::", stringify!($mod_name), ";\\n",
1595 "use std::io::Write;\\n",
1596 "\\n",
1597 "let mut output = Vec::new();\\n",
1598 "let mut writer = ", stringify!($mod_name), "::encode_writer(&mut output);\\n",
1599 "writer.write_all(b\\\"Hello\\\").unwrap();\\n",
1600 "writer.flush().unwrap();\\n",
1601 "```\\n"
1602 )]
1603 pub const fn encode_writer<W: std::io::Write>(inner: W) -> super::EncodeWriter<W, $n> {
1604 super::EncodeWriter::new(inner, STD)
1605 }
1606
1607 #[doc = concat!(
1608 "Creates a decoding writer that wraps an `io::Write`.\\n\\n",
1609 "The writer buffers ", stringify!($mod_name), " encoded bytes with padding, ",
1610 "decodes them, and writes the raw output to the inner writer.\\n\\n",
1611 "# Examples\\n\\n",
1612 "```\\n",
1613 "use omp_core::", stringify!($mod_name), ";\\n",
1614 "use std::io::Write;\\n",
1615 "\\n",
1616 "let mut output = Vec::new();\\n",
1617 "let encoded = ", stringify!($mod_name), "::encode(b\\\"Hello\\\").into_vec();\\n",
1618 "let mut writer = ", stringify!($mod_name), "::decode_writer(&mut output);\\n",
1619 "writer.write_all(&encoded).unwrap();\\n",
1620 "writer.flush().unwrap();\\n",
1621 "assert_eq!(output, b\\\"Hello\\\");\\n",
1622 "```\\n"
1623 )]
1624 pub const fn decode_writer<W: std::io::Write>(inner: W) -> super::DecodeWriter<W, $n> {
1625 super::DecodeWriter::new(inner, STD)
1626 }
1627
1628 #[doc = concat!(
1629 "Creates an encoding writer for unpadded ", stringify!($mod_name), ".\\n\\n",
1630 "The writer buffers raw bytes, encodes them to ", stringify!($mod_name), " without padding, ",
1631 "and writes the encoded output to the inner writer.\\n\\n",
1632 "# Examples\\n\\n",
1633 "```\\n",
1634 "use omp_core::", stringify!($mod_name), ";\\n",
1635 "use std::io::Write;\\n",
1636 "\\n",
1637 "let mut output = Vec::new();\\n",
1638 "let mut writer = ", stringify!($mod_name), "::encode_writer_raw(&mut output);\\n",
1639 "writer.write_all(b\\\"Hello\\\").unwrap();\\n",
1640 "writer.flush().unwrap();\\n",
1641 "```\\n"
1642 )]
1643 pub const fn encode_writer_raw<W: std::io::Write>(inner: W) -> super::EncodeWriter<W, $n> {
1644 super::EncodeWriter::new(inner, RAW)
1645 }
1646
1647 #[doc = concat!(
1648 "Creates a decoding writer for unpadded ", stringify!($mod_name), ".\\n\\n",
1649 "The writer buffers ", stringify!($mod_name), " encoded bytes without padding, ",
1650 "decodes them, and writes the raw output to the inner writer.\\n\\n",
1651 "# Examples\\n\\n",
1652 "```\\n",
1653 "use omp_core::", stringify!($mod_name), ";\\n",
1654 "use std::io::Write;\\n",
1655 "\\n",
1656 "let mut output = Vec::new();\\n",
1657 "let encoded = ", stringify!($mod_name), "::encode_raw(b\\\"Hello\\\").into_vec();\\n",
1658 "let mut writer = ", stringify!($mod_name), "::decode_writer_raw(&mut output);\\n",
1659 "writer.write_all(&encoded).unwrap();\\n",
1660 "writer.flush().unwrap();\\n",
1661 "assert_eq!(output, b\\\"Hello\\\");\\n",
1662 "```\\n"
1663 )]
1664 pub const fn decode_writer_raw<W: std::io::Write>(inner: W) -> super::DecodeWriter<W, $n> {
1665 super::DecodeWriter::new(inner, RAW)
1666 }
1667 }
1668 };
1669}
1670
1671define_encoding!(
1673 base64,
1674 64,
1675 b'=',
1676 b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
1677 false
1678);
1679define_encoding!(
1680 base64_url,
1681 64,
1682 b'=',
1683 b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
1684 false
1685);
1686
1687define_encoding!(base32, 32, b'=', b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", false);
1689define_encoding!(base32_hex, 32, b'=', b"0123456789ABCDEFGHIJKLMNOPQRSTUV", false);
1690define_encoding!(base32_dns, 32, b'=', b"0123456789abcdefghijklmnopqrstuv", false);