qubit_codec_misc/
form_urlencoded_codec.rs1use crate::percent_codec::{
11 percent_decode_byte,
12 percent_decode_bytes,
13 percent_encode_byte,
14 percent_encode_bytes,
15};
16use crate::{
17 Codec,
18 MiscCodecError,
19 MiscCodecResult,
20 ValueDecoder,
21 ValueEncoder,
22};
23
24#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
30pub struct FormUrlencodedCodec;
31
32impl FormUrlencodedCodec {
33 #[inline]
38 pub fn new() -> Self {
39 Self
40 }
41
42 #[inline]
50 pub fn encode(&self, text: &str) -> String {
51 percent_encode_bytes(text.as_bytes(), true)
52 }
53
54 #[inline]
66 pub fn decode(&self, text: &str) -> MiscCodecResult<String> {
67 String::from_utf8(percent_decode_bytes(text, true)?)
68 .map_err(MiscCodecError::from)
69 }
70}
71
72impl ValueEncoder<str> for FormUrlencodedCodec {
73 type Error = MiscCodecError;
74 type Output = String;
75
76 #[inline]
78 fn encode(&self, input: &str) -> Result<Self::Output, Self::Error> {
79 Ok(FormUrlencodedCodec::encode(self, input))
80 }
81}
82
83impl ValueDecoder<str> for FormUrlencodedCodec {
84 type Error = MiscCodecError;
85 type Output = String;
86
87 #[inline]
89 fn decode(&self, input: &str) -> Result<Self::Output, Self::Error> {
90 FormUrlencodedCodec::decode(self, input)
91 }
92}
93
94unsafe impl Codec for FormUrlencodedCodec {
95 type Value = u8;
96 type Unit = u8;
97 type DecodeError = MiscCodecError;
98 type EncodeError = MiscCodecError;
99
100 #[inline(always)]
102 fn min_units_per_value(&self) -> core::num::NonZeroUsize {
103 core::num::NonZeroUsize::MIN
104 }
105
106 #[inline(always)]
108 fn max_units_per_value(&self) -> core::num::NonZeroUsize {
109 unsafe { core::num::NonZeroUsize::new_unchecked(3) }
110 }
111
112 #[inline]
114 unsafe fn decode_unchecked(
115 &self,
116 input: &[u8],
117 index: usize,
118 ) -> Result<(u8, core::num::NonZeroUsize), Self::DecodeError> {
119 debug_assert!(index < input.len());
120
121 let (value, consumed) = percent_decode_byte(input, index, true)?;
122 debug_assert!(consumed > 0);
123 let consumed =
126 unsafe { core::num::NonZeroUsize::new_unchecked(consumed) };
127 Ok((value, consumed))
128 }
129
130 #[inline]
132 unsafe fn encode_unchecked(
133 &self,
134 value: &u8,
135 output: &mut [u8],
136 index: usize,
137 ) -> Result<usize, Self::EncodeError> {
138 debug_assert!(
139 index
140 + if *value == b' '
141 || value.is_ascii_alphanumeric()
142 || matches!(*value, b'-' | b'.' | b'_' | b'~')
143 {
144 1
145 } else {
146 3
147 }
148 <= output.len()
149 );
150
151 Ok(percent_encode_byte(*value, output, index, true))
152 }
153}