1use o3::buffer::{Bytes, Retained, Shared};
2
3use crate::Result;
4use crate::body::InlineToken;
5use crate::error::Fail;
6use crate::scan::Scan;
7
8pub struct Parse;
9
10impl Parse {
11 pub fn frame(owner: &Shared, idx: &mut usize) -> Result<Bytes<Retained>> {
12 let input = owner.as_slice();
13 if *idx >= input.len() {
14 return Err(Fail::bad());
15 }
16 if input[*idx] == b'"' {
17 let start = *idx;
18 let _ = Scan::str_slice(input, idx)?;
19 let raw_start = start.saturating_add(1);
20 let raw_end = idx.saturating_sub(1);
21 if raw_end < raw_start {
22 return Err(Fail::bad());
23 }
24 let mut esc = raw_start;
25 while esc < raw_end {
26 if input[esc] == b'\\' {
27 let decoded = Shared::from(Scan::decode_str(&input[raw_start..raw_end])?);
28 return Ok(Bytes::<Retained>::from(decoded));
29 }
30 esc += 1;
31 }
32 return Ok(Bytes::<Retained>::from(owner.slice(raw_start..raw_end)));
33 }
34 let start = *idx;
35 Scan::skip_value(input, idx)?;
36 let end = *idx;
37 if end <= start {
38 return Err(Fail::bad());
39 }
40 Ok(Bytes::<Retained>::from(owner.slice(start..end)))
41 }
42
43 pub fn empty_frame() -> Bytes<Retained> {
44 Bytes::<Retained>::from(Shared::new())
45 }
46
47 pub fn frame_plain(owner: &Shared, idx: &mut usize) -> Result<Bytes<Retained>> {
48 let input = owner.as_slice();
49 Scan::expect_byte(input, idx, b'"')?;
50 let start = *idx;
51 while *idx < input.len() {
52 match input[*idx] {
53 b'"' => {
54 let end = *idx;
55 *idx += 1;
56 return Ok(Bytes::<Retained>::from(owner.slice(start..end)));
57 }
58 b'\\' => return Err(Fail::bad()),
59 _ => *idx += 1,
60 }
61 }
62 Err(Fail::bad())
63 }
64
65 pub fn inline_plain<const N: usize>(input: &[u8], idx: &mut usize) -> Result<InlineToken<N>> {
66 Scan::expect_byte(input, idx, b'"')?;
67 let mut out = InlineToken::<N>::new();
68 while *idx < input.len() {
69 match input[*idx] {
70 b'"' => {
71 *idx += 1;
72 return Ok(out);
73 }
74 b'\\' => return Err(Fail::bad()),
75 b => {
76 out.push(b)?;
77 *idx += 1;
78 }
79 }
80 }
81 Err(Fail::bad())
82 }
83
84 pub fn frame_raw(owner: &Shared, idx: &mut usize) -> Result<Bytes<Retained>> {
85 let input = owner.as_slice();
86 let start = *idx;
87 while *idx < input.len() {
88 match input[*idx] {
89 b',' | b'}' | b']' => break,
90 _ => *idx += 1,
91 }
92 }
93 let end = *idx;
94 if end <= start {
95 return Err(Fail::bad());
96 }
97 Ok(Bytes::<Retained>::from(owner.slice(start..end)))
98 }
99
100 pub fn inline_raw<const N: usize>(input: &[u8], idx: &mut usize) -> Result<InlineToken<N>> {
101 let mut out = InlineToken::<N>::new();
102 while *idx < input.len() {
103 match input[*idx] {
104 b',' | b'}' | b']' => break,
105 b => {
106 out.push(b)?;
107 *idx += 1;
108 }
109 }
110 }
111 if out.is_empty() {
112 return Err(Fail::bad());
113 }
114 Ok(out)
115 }
116
117 pub fn u64(input: &[u8], idx: &mut usize) -> Result<u64> {
118 if *idx >= input.len() {
119 return Err(Fail::bad());
120 }
121 let mut value = 0u64;
122 let mut seen = false;
123 while *idx < input.len() {
124 let b = input[*idx];
125 if !b.is_ascii_digit() {
126 break;
127 }
128 value = value
129 .checked_mul(10)
130 .and_then(|v| v.checked_add((b - b'0') as u64))
131 .ok_or_else(Fail::bad)?;
132 *idx += 1;
133 seen = true;
134 }
135 if !seen {
136 return Err(Fail::bad());
137 }
138 Ok(value)
139 }
140
141 pub fn bool(input: &[u8], idx: &mut usize) -> Result<bool> {
142 if input.get(*idx..(*idx + 4)) == Some(b"true") {
143 *idx += 4;
144 return Ok(true);
145 }
146 if input.get(*idx..(*idx + 5)) == Some(b"false") {
147 *idx += 5;
148 return Ok(false);
149 }
150 Err(Fail::bad())
151 }
152}