`bytes()`, empty, `n` zero bytes, iter of ints (0..=255), or `(str, encoding)`. Encodings limited to utf-8/utf8/ascii; unknown ones error so mismatches aren't silent. */
(&mut self, argc: u16)
| 168 | |
| 169 | /* `bytes()`, empty, `n` zero bytes, iter of ints (0..=255), or `(str, encoding)`. Encodings limited to utf-8/utf8/ascii; unknown ones error so mismatches aren't silent. */ |
| 170 | pub fn call_bytes(&mut self, argc: u16) -> Result<(), VmErr> { |
| 171 | let args = self.pop_n(argc as usize)?; |
| 172 | let buf: Vec<u8> = match args.len() { |
| 173 | 0 => Vec::new(), |
| 174 | 1 => { |
| 175 | let a = args[0]; |
| 176 | if a.is_int() { |
| 177 | let n = a.as_int(); |
| 178 | if n < 0 { return Err(cold_value("negative count")); } |
| 179 | // Length is user-controlled; cap it against the heap budget so a huge count errors instead of aborting in the allocator. |
| 180 | if n as usize > self.heap.limit() { return Err(cold_heap()); } |
| 181 | alloc::vec![0u8; n as usize] |
| 182 | } else if a.is_heap() { |
| 183 | if let HeapObj::Bytes(b) = self.heap.get(a) { |
| 184 | b.clone() |
| 185 | } else { |
| 186 | let items = self.iter_to_vec_general(a)?; |
| 187 | let mut out = Vec::with_capacity(items.len()); |
| 188 | for v in items { |
| 189 | if !v.is_int() { |
| 190 | return Err(cold_type("bytes() iterable must contain ints")); |
| 191 | } |
| 192 | let n = v.as_int(); |
| 193 | if !(0..=255).contains(&n) { |
| 194 | return Err(cold_value("bytes must be in range(0, 256)")); |
| 195 | } |
| 196 | out.push(n as u8); |
| 197 | } |
| 198 | out |
| 199 | } |
| 200 | } else { |
| 201 | return Err(cold_type("bytes() requires an int, an iterable of ints, or (str, encoding)")); |
| 202 | } |
| 203 | } |
| 204 | 2 => { |
| 205 | // `bytes(s, "utf-8")`, string encoding form. |
| 206 | let (s, enc) = (args[0], args[1]); |
| 207 | let Some(HeapObj::Str(text)) = self.heap.try_get(s).cloned() else { |
| 208 | return Err(cold_type("bytes() first argument must be a string when encoding is given")); |
| 209 | }; |
| 210 | let Some(HeapObj::Str(encoding)) = self.heap.try_get(enc) else { |
| 211 | return Err(cold_type("bytes() encoding must be a string")); |
| 212 | }; |
| 213 | match encoding.as_str() { |
| 214 | "utf-8" | "utf8" => text.into_bytes(), |
| 215 | "ascii" => { |
| 216 | if !text.is_ascii() { |
| 217 | return Err(cold_value("'ascii' codec can't encode non-ASCII characters")); |
| 218 | } |
| 219 | text.into_bytes() |
| 220 | } |
| 221 | _ => return Err(cold_value("unsupported encoding (expected 'utf-8' or 'ascii')")), |
| 222 | } |
| 223 | } |
| 224 | _ => return Err(cold_type("bytes() takes at most 2 arguments")), |
| 225 | }; |
| 226 | let v = self.heap.alloc(HeapObj::Bytes(buf))?; |
| 227 | self.push(v); Ok(()) |
no test coverage detected