1use super::{
2 PositionIterInternal, PyDictRef, PyIntRef, PyStrRef, PyTuple, PyTupleRef, PyType, PyTypeRef,
3};
4use crate::{
5 anystr::{self, AnyStr},
6 atomic_func,
7 bytesinner::{
8 bytes_decode, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions,
9 ByteInnerSplitOptions, ByteInnerTranslateOptions, DecodeArgs, PyBytesInner,
10 },
11 class::PyClassImpl,
12 common::{hash::PyHash, lock::PyMutex},
13 convert::{ToPyObject, ToPyResult},
14 function::{
15 ArgBytesLike, ArgIndex, ArgIterable, Either, OptionalArg, OptionalOption, PyComparisonValue,
16 },
17 protocol::{
18 BufferDescriptor, BufferMethods, PyBuffer, PyIterReturn, PyMappingMethods, PyNumberMethods,
19 PySequenceMethods,
20 },
21 sliceable::{SequenceIndex, SliceableSequenceOp},
22 types::{
23 AsBuffer, AsMapping, AsNumber, AsSequence, Callable, Comparable, Constructor, Hashable,
24 IterNext, Iterable, PyComparisonOp, Representable, SelfIter, Unconstructible,
25 },
26 AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
27 TryFromBorrowedObject, TryFromObject, VirtualMachine,
28};
29use bstr::ByteSlice;
30use once_cell::sync::Lazy;
31use std::{mem::size_of, ops::Deref};
32
33#[pyclass(module = false, name = "bytes")]
34#[derive(Clone, Debug)]
35pub struct PyBytes {
36 inner: PyBytesInner,
37}
38
39pub type PyBytesRef = PyRef<PyBytes>;
40
41impl From<Vec<u8>> for PyBytes {
42 fn from(elements: Vec<u8>) -> Self {
43 Self {
44 inner: PyBytesInner { elements },
45 }
46 }
47}
48
49impl From<PyBytesInner> for PyBytes {
50 fn from(inner: PyBytesInner) -> Self {
51 Self { inner }
52 }
53}
54
55impl ToPyObject for Vec<u8> {
56 fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
57 vm.ctx.new_bytes(self).into()
58 }
59}
60
61impl Deref for PyBytes {
62 type Target = [u8];
63
64 fn deref(&self) -> &[u8] {
65 self.as_bytes()
66 }
67}
68
69impl AsRef<[u8]> for PyBytes {
70 fn as_ref(&self) -> &[u8] {
71 self.as_bytes()
72 }
73}
74impl AsRef<[u8]> for PyBytesRef {
75 fn as_ref(&self) -> &[u8] {
76 self.as_bytes()
77 }
78}
79
80impl PyPayload for PyBytes {
81 fn class(ctx: &Context) -> &'static Py<PyType> {
82 ctx.types.bytes_type
83 }
84}
85
86pub(crate) fn init(context: &Context) {
87 PyBytes::extend_class(context, context.types.bytes_type);
88 PyBytesIterator::extend_class(context, context.types.bytes_iterator_type);
89}
90
91impl Constructor for PyBytes {
92 type Args = ByteInnerNewOptions;
93
94 fn py_new(cls: PyTypeRef, options: Self::Args, vm: &VirtualMachine) -> PyResult {
95 options.get_bytes(cls, vm).to_pyresult(vm)
96 }
97}
98
99impl PyBytes {
100 pub fn new_ref(data: Vec<u8>, ctx: &Context) -> PyRef<Self> {
101 PyRef::new_ref(Self::from(data), ctx.types.bytes_type.to_owned(), None)
102 }
103
104 fn _getitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult {
105 match SequenceIndex::try_from_borrowed_object(vm, needle, "byte")? {
106 SequenceIndex::Int(i) => self
107 .getitem_by_index(vm, i)
108 .map(|x| vm.ctx.new_int(x).into()),
109 SequenceIndex::Slice(slice) => self
110 .getitem_by_slice(vm, slice)
111 .map(|x| vm.ctx.new_bytes(x).into()),
112 }
113 }
114}
115
116impl PyRef<PyBytes> {
117 fn repeat(self, count: isize, vm: &VirtualMachine) -> PyResult<PyRef<PyBytes>> {
118 if count == 1 && self.class().is(vm.ctx.types.bytes_type) {
119 return Ok(self);
124 }
125 self.inner
126 .mul(count, vm)
127 .map(|x| PyBytes::from(x).into_ref(&vm.ctx))
128 }
129}
130
131#[pyclass(
132 flags(BASETYPE),
133 with(
134 Py,
135 PyRef,
136 AsMapping,
137 AsSequence,
138 Hashable,
139 Comparable,
140 AsBuffer,
141 Iterable,
142 Constructor,
143 AsNumber,
144 Representable,
145 )
146)]
147impl PyBytes {
148 #[pymethod(magic)]
149 #[inline]
150 pub fn len(&self) -> usize {
151 self.inner.len()
152 }
153
154 #[inline]
155 pub fn is_empty(&self) -> bool {
156 self.inner.is_empty()
157 }
158
159 #[inline]
160 pub fn as_bytes(&self) -> &[u8] {
161 self.inner.as_bytes()
162 }
163
164 #[pymethod(magic)]
165 fn sizeof(&self) -> usize {
166 size_of::<Self>() + self.len() * size_of::<u8>()
167 }
168
169 #[pymethod(magic)]
170 fn add(&self, other: ArgBytesLike) -> Vec<u8> {
171 self.inner.add(&other.borrow_buf())
172 }
173
174 #[pymethod(magic)]
175 fn contains(
176 &self,
177 needle: Either<PyBytesInner, PyIntRef>,
178 vm: &VirtualMachine,
179 ) -> PyResult<bool> {
180 self.inner.contains(needle, vm)
181 }
182
183 #[pystaticmethod]
184 fn maketrans(from: PyBytesInner, to: PyBytesInner, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
185 PyBytesInner::maketrans(from, to, vm)
186 }
187
188 #[pymethod(magic)]
189 fn getitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
190 self._getitem(&needle, vm)
191 }
192
193 #[pymethod]
194 fn isalnum(&self) -> bool {
195 self.inner.isalnum()
196 }
197
198 #[pymethod]
199 fn isalpha(&self) -> bool {
200 self.inner.isalpha()
201 }
202
203 #[pymethod]
204 fn isascii(&self) -> bool {
205 self.inner.isascii()
206 }
207
208 #[pymethod]
209 fn isdigit(&self) -> bool {
210 self.inner.isdigit()
211 }
212
213 #[pymethod]
214 fn islower(&self) -> bool {
215 self.inner.islower()
216 }
217
218 #[pymethod]
219 fn isspace(&self) -> bool {
220 self.inner.isspace()
221 }
222
223 #[pymethod]
224 fn isupper(&self) -> bool {
225 self.inner.isupper()
226 }
227
228 #[pymethod]
229 fn istitle(&self) -> bool {
230 self.inner.istitle()
231 }
232
233 #[pymethod]
234 fn lower(&self) -> Self {
235 self.inner.lower().into()
236 }
237
238 #[pymethod]
239 fn upper(&self) -> Self {
240 self.inner.upper().into()
241 }
242
243 #[pymethod]
244 fn capitalize(&self) -> Self {
245 self.inner.capitalize().into()
246 }
247
248 #[pymethod]
249 fn swapcase(&self) -> Self {
250 self.inner.swapcase().into()
251 }
252
253 #[pymethod]
254 pub(crate) fn hex(
255 &self,
256 sep: OptionalArg<Either<PyStrRef, PyBytesRef>>,
257 bytes_per_sep: OptionalArg<isize>,
258 vm: &VirtualMachine,
259 ) -> PyResult<String> {
260 self.inner.hex(sep, bytes_per_sep, vm)
261 }
262
263 #[pyclassmethod]
264 fn fromhex(cls: PyTypeRef, string: PyStrRef, vm: &VirtualMachine) -> PyResult {
265 let bytes = PyBytesInner::fromhex(string.as_str(), vm)?;
266 let bytes = vm.ctx.new_bytes(bytes).into();
267 PyType::call(&cls, vec![bytes].into(), vm)
268 }
269
270 #[pymethod]
271 fn center(&self, options: ByteInnerPaddingOptions, vm: &VirtualMachine) -> PyResult<PyBytes> {
272 Ok(self.inner.center(options, vm)?.into())
273 }
274
275 #[pymethod]
276 fn ljust(&self, options: ByteInnerPaddingOptions, vm: &VirtualMachine) -> PyResult<PyBytes> {
277 Ok(self.inner.ljust(options, vm)?.into())
278 }
279
280 #[pymethod]
281 fn rjust(&self, options: ByteInnerPaddingOptions, vm: &VirtualMachine) -> PyResult<PyBytes> {
282 Ok(self.inner.rjust(options, vm)?.into())
283 }
284
285 #[pymethod]
286 fn count(&self, options: ByteInnerFindOptions, vm: &VirtualMachine) -> PyResult<usize> {
287 self.inner.count(options, vm)
288 }
289
290 #[pymethod]
291 fn join(&self, iter: ArgIterable<PyBytesInner>, vm: &VirtualMachine) -> PyResult<PyBytes> {
292 Ok(self.inner.join(iter, vm)?.into())
293 }
294
295 #[pymethod]
296 fn endswith(&self, options: anystr::StartsEndsWithArgs, vm: &VirtualMachine) -> PyResult<bool> {
297 let (affix, substr) =
298 match options.prepare(self.as_bytes(), self.len(), |s, r| s.get_bytes(r)) {
299 Some(x) => x,
300 None => return Ok(false),
301 };
302 substr.py_startsendswith(
303 &affix,
304 "endswith",
305 "bytes",
306 |s, x: PyBytesInner| s.ends_with(x.as_bytes()),
307 vm,
308 )
309 }
310
311 #[pymethod]
312 fn startswith(
313 &self,
314 options: anystr::StartsEndsWithArgs,
315 vm: &VirtualMachine,
316 ) -> PyResult<bool> {
317 let (affix, substr) =
318 match options.prepare(self.as_bytes(), self.len(), |s, r| s.get_bytes(r)) {
319 Some(x) => x,
320 None => return Ok(false),
321 };
322 substr.py_startsendswith(
323 &affix,
324 "startswith",
325 "bytes",
326 |s, x: PyBytesInner| s.starts_with(x.as_bytes()),
327 vm,
328 )
329 }
330
331 #[pymethod]
332 fn find(&self, options: ByteInnerFindOptions, vm: &VirtualMachine) -> PyResult<isize> {
333 let index = self.inner.find(options, |h, n| h.find(n), vm)?;
334 Ok(index.map_or(-1, |v| v as isize))
335 }
336
337 #[pymethod]
338 fn index(&self, options: ByteInnerFindOptions, vm: &VirtualMachine) -> PyResult<usize> {
339 let index = self.inner.find(options, |h, n| h.find(n), vm)?;
340 index.ok_or_else(|| vm.new_value_error("substring not found".to_owned()))
341 }
342
343 #[pymethod]
344 fn rfind(&self, options: ByteInnerFindOptions, vm: &VirtualMachine) -> PyResult<isize> {
345 let index = self.inner.find(options, |h, n| h.rfind(n), vm)?;
346 Ok(index.map_or(-1, |v| v as isize))
347 }
348
349 #[pymethod]
350 fn rindex(&self, options: ByteInnerFindOptions, vm: &VirtualMachine) -> PyResult<usize> {
351 let index = self.inner.find(options, |h, n| h.rfind(n), vm)?;
352 index.ok_or_else(|| vm.new_value_error("substring not found".to_owned()))
353 }
354
355 #[pymethod]
356 fn translate(
357 &self,
358 options: ByteInnerTranslateOptions,
359 vm: &VirtualMachine,
360 ) -> PyResult<PyBytes> {
361 Ok(self.inner.translate(options, vm)?.into())
362 }
363
364 #[pymethod]
365 fn strip(&self, chars: OptionalOption<PyBytesInner>) -> Self {
366 self.inner.strip(chars).into()
367 }
368
369 #[pymethod]
370 fn removeprefix(&self, prefix: PyBytesInner) -> Self {
371 self.inner.removeprefix(prefix).into()
372 }
373
374 #[pymethod]
375 fn removesuffix(&self, suffix: PyBytesInner) -> Self {
376 self.inner.removesuffix(suffix).into()
377 }
378
379 #[pymethod]
380 fn split(
381 &self,
382 options: ByteInnerSplitOptions,
383 vm: &VirtualMachine,
384 ) -> PyResult<Vec<PyObjectRef>> {
385 self.inner
386 .split(options, |s, vm| vm.ctx.new_bytes(s.to_vec()).into(), vm)
387 }
388
389 #[pymethod]
390 fn rsplit(
391 &self,
392 options: ByteInnerSplitOptions,
393 vm: &VirtualMachine,
394 ) -> PyResult<Vec<PyObjectRef>> {
395 self.inner
396 .rsplit(options, |s, vm| vm.ctx.new_bytes(s.to_vec()).into(), vm)
397 }
398
399 #[pymethod]
400 fn partition(&self, sep: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
401 let sub = PyBytesInner::try_from_borrowed_object(vm, &sep)?;
402 let (front, has_mid, back) = self.inner.partition(&sub, vm)?;
403 Ok(vm.new_tuple((
404 vm.ctx.new_bytes(front),
405 if has_mid {
406 sep
407 } else {
408 vm.ctx.new_bytes(Vec::new()).into()
409 },
410 vm.ctx.new_bytes(back),
411 )))
412 }
413
414 #[pymethod]
415 fn rpartition(&self, sep: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
416 let sub = PyBytesInner::try_from_borrowed_object(vm, &sep)?;
417 let (back, has_mid, front) = self.inner.rpartition(&sub, vm)?;
418 Ok(vm.new_tuple((
419 vm.ctx.new_bytes(front),
420 if has_mid {
421 sep
422 } else {
423 vm.ctx.new_bytes(Vec::new()).into()
424 },
425 vm.ctx.new_bytes(back),
426 )))
427 }
428
429 #[pymethod]
430 fn expandtabs(&self, options: anystr::ExpandTabsArgs) -> Self {
431 self.inner.expandtabs(options).into()
432 }
433
434 #[pymethod]
435 fn splitlines(&self, options: anystr::SplitLinesArgs, vm: &VirtualMachine) -> Vec<PyObjectRef> {
436 self.inner
437 .splitlines(options, |x| vm.ctx.new_bytes(x.to_vec()).into())
438 }
439
440 #[pymethod]
441 fn zfill(&self, width: isize) -> Self {
442 self.inner.zfill(width).into()
443 }
444
445 #[pymethod]
446 fn replace(
447 &self,
448 old: PyBytesInner,
449 new: PyBytesInner,
450 count: OptionalArg<isize>,
451 vm: &VirtualMachine,
452 ) -> PyResult<PyBytes> {
453 Ok(self.inner.replace(old, new, count, vm)?.into())
454 }
455
456 #[pymethod]
457 fn title(&self) -> Self {
458 self.inner.title().into()
459 }
460
461 #[pymethod(name = "__rmul__")]
462 #[pymethod(magic)]
463 fn mul(zelf: PyRef<Self>, value: ArgIndex, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
464 zelf.repeat(value.try_to_primitive(vm)?, vm)
465 }
466
467 #[pymethod(name = "__mod__")]
468 fn mod_(&self, values: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyBytes> {
469 let formatted = self.inner.cformat(values, vm)?;
470 Ok(formatted.into())
471 }
472
473 #[pymethod(magic)]
474 fn rmod(&self, _values: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
475 vm.ctx.not_implemented()
476 }
477
478 #[pymethod(magic)]
479 fn getnewargs(&self, vm: &VirtualMachine) -> PyTupleRef {
480 let param: Vec<PyObjectRef> = self.elements().map(|x| x.to_pyobject(vm)).collect();
481 PyTuple::new_ref(param, &vm.ctx)
482 }
483}
484
485#[pyclass]
486impl Py<PyBytes> {
487 #[pymethod(magic)]
488 fn reduce_ex(
489 &self,
490 _proto: usize,
491 vm: &VirtualMachine,
492 ) -> (PyTypeRef, PyTupleRef, Option<PyDictRef>) {
493 Self::reduce(self, vm)
494 }
495
496 #[pymethod(magic)]
497 fn reduce(&self, vm: &VirtualMachine) -> (PyTypeRef, PyTupleRef, Option<PyDictRef>) {
498 let bytes = PyBytes::from(self.to_vec()).to_pyobject(vm);
499 (
500 self.class().to_owned(),
501 PyTuple::new_ref(vec![bytes], &vm.ctx),
502 self.as_object().dict(),
503 )
504 }
505}
506
507#[pyclass]
508impl PyRef<PyBytes> {
509 #[pymethod(magic)]
510 fn bytes(self, vm: &VirtualMachine) -> PyRef<PyBytes> {
511 if self.is(vm.ctx.types.bytes_type) {
512 self
513 } else {
514 PyBytes::from(self.inner.clone()).into_ref(&vm.ctx)
515 }
516 }
517
518 #[pymethod]
519 fn lstrip(self, chars: OptionalOption<PyBytesInner>, vm: &VirtualMachine) -> PyRef<PyBytes> {
520 let stripped = self.inner.lstrip(chars);
521 if stripped == self.as_bytes() {
522 self
523 } else {
524 vm.ctx.new_bytes(stripped.to_vec())
525 }
526 }
527
528 #[pymethod]
529 fn rstrip(self, chars: OptionalOption<PyBytesInner>, vm: &VirtualMachine) -> PyRef<PyBytes> {
530 let stripped = self.inner.rstrip(chars);
531 if stripped == self.as_bytes() {
532 self
533 } else {
534 vm.ctx.new_bytes(stripped.to_vec())
535 }
536 }
537
538 #[pymethod]
546 fn decode(self, args: DecodeArgs, vm: &VirtualMachine) -> PyResult<PyStrRef> {
547 bytes_decode(self.into(), args, vm)
548 }
549}
550
551static BUFFER_METHODS: BufferMethods = BufferMethods {
552 obj_bytes: |buffer| buffer.obj_as::<PyBytes>().as_bytes().into(),
553 obj_bytes_mut: |_| panic!(),
554 release: |_| {},
555 retain: |_| {},
556};
557
558impl AsBuffer for PyBytes {
559 fn as_buffer(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<PyBuffer> {
560 let buf = PyBuffer::new(
561 zelf.to_owned().into(),
562 BufferDescriptor::simple(zelf.len(), true),
563 &BUFFER_METHODS,
564 );
565 Ok(buf)
566 }
567}
568
569impl AsMapping for PyBytes {
570 fn as_mapping() -> &'static PyMappingMethods {
571 static AS_MAPPING: Lazy<PyMappingMethods> = Lazy::new(|| PyMappingMethods {
572 length: atomic_func!(|mapping, _vm| Ok(PyBytes::mapping_downcast(mapping).len())),
573 subscript: atomic_func!(
574 |mapping, needle, vm| PyBytes::mapping_downcast(mapping)._getitem(needle, vm)
575 ),
576 ..PyMappingMethods::NOT_IMPLEMENTED
577 });
578 &AS_MAPPING
579 }
580}
581
582impl AsSequence for PyBytes {
583 fn as_sequence() -> &'static PySequenceMethods {
584 static AS_SEQUENCE: Lazy<PySequenceMethods> = Lazy::new(|| PySequenceMethods {
585 length: atomic_func!(|seq, _vm| Ok(PyBytes::sequence_downcast(seq).len())),
586 concat: atomic_func!(|seq, other, vm| {
587 PyBytes::sequence_downcast(seq)
588 .inner
589 .concat(other, vm)
590 .map(|x| vm.ctx.new_bytes(x).into())
591 }),
592 repeat: atomic_func!(|seq, n, vm| {
593 let zelf = seq.obj.to_owned().downcast::<PyBytes>().map_err(|_| {
594 vm.new_type_error("bad argument type for built-in operation".to_owned())
595 })?;
596 zelf.repeat(n, vm).to_pyresult(vm)
597 }),
598 item: atomic_func!(|seq, i, vm| {
599 PyBytes::sequence_downcast(seq)
600 .as_bytes()
601 .getitem_by_index(vm, i)
602 .map(|x| vm.ctx.new_bytes(vec![x]).into())
603 }),
604 contains: atomic_func!(|seq, other, vm| {
605 let other =
606 <Either<PyBytesInner, PyIntRef>>::try_from_object(vm, other.to_owned())?;
607 PyBytes::sequence_downcast(seq).contains(other, vm)
608 }),
609 ..PySequenceMethods::NOT_IMPLEMENTED
610 });
611 &AS_SEQUENCE
612 }
613}
614
615impl AsNumber for PyBytes {
616 fn as_number() -> &'static PyNumberMethods {
617 static AS_NUMBER: PyNumberMethods = PyNumberMethods {
618 remainder: Some(|a, b, vm| {
619 if let Some(a) = a.downcast_ref::<PyBytes>() {
620 a.mod_(b.to_owned(), vm).to_pyresult(vm)
621 } else {
622 Ok(vm.ctx.not_implemented())
623 }
624 }),
625 ..PyNumberMethods::NOT_IMPLEMENTED
626 };
627 &AS_NUMBER
628 }
629}
630
631impl Hashable for PyBytes {
632 #[inline]
633 fn hash(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyHash> {
634 Ok(zelf.inner.hash(vm))
635 }
636}
637
638impl Comparable for PyBytes {
639 fn cmp(
640 zelf: &Py<Self>,
641 other: &PyObject,
642 op: PyComparisonOp,
643 vm: &VirtualMachine,
644 ) -> PyResult<PyComparisonValue> {
645 Ok(if let Some(res) = op.identical_optimization(zelf, other) {
646 res.into()
647 } else if other.fast_isinstance(vm.ctx.types.memoryview_type)
648 && op != PyComparisonOp::Eq
649 && op != PyComparisonOp::Ne
650 {
651 return Err(vm.new_type_error(format!(
652 "'{}' not supported between instances of '{}' and '{}'",
653 op.operator_token(),
654 zelf.class().name(),
655 other.class().name()
656 )));
657 } else {
658 zelf.inner.cmp(other, op, vm)
659 })
660 }
661}
662
663impl Iterable for PyBytes {
664 fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
665 Ok(PyBytesIterator {
666 internal: PyMutex::new(PositionIterInternal::new(zelf, 0)),
667 }
668 .into_pyobject(vm))
669 }
670}
671
672impl Representable for PyBytes {
673 #[inline]
674 fn repr_str(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
675 zelf.inner.repr_bytes(vm)
676 }
677}
678
679#[pyclass(module = false, name = "bytes_iterator")]
680#[derive(Debug)]
681pub struct PyBytesIterator {
682 internal: PyMutex<PositionIterInternal<PyBytesRef>>,
683}
684
685impl PyPayload for PyBytesIterator {
686 fn class(ctx: &Context) -> &'static Py<PyType> {
687 ctx.types.bytes_iterator_type
688 }
689}
690
691#[pyclass(with(Unconstructible, IterNext, Iterable))]
692impl PyBytesIterator {
693 #[pymethod(magic)]
694 fn length_hint(&self) -> usize {
695 self.internal.lock().length_hint(|obj| obj.len())
696 }
697
698 #[pymethod(magic)]
699 fn reduce(&self, vm: &VirtualMachine) -> PyTupleRef {
700 self.internal
701 .lock()
702 .builtins_iter_reduce(|x| x.clone().into(), vm)
703 }
704
705 #[pymethod(magic)]
706 fn setstate(&self, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
707 self.internal
708 .lock()
709 .set_state(state, |obj, pos| pos.min(obj.len()), vm)
710 }
711}
712impl Unconstructible for PyBytesIterator {}
713
714impl SelfIter for PyBytesIterator {}
715impl IterNext for PyBytesIterator {
716 fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
717 zelf.internal.lock().next(|bytes, pos| {
718 Ok(PyIterReturn::from_result(
719 bytes
720 .as_bytes()
721 .get(pos)
722 .map(|&x| vm.new_pyobj(x))
723 .ok_or(None),
724 ))
725 })
726 }
727}
728
729impl<'a> TryFromBorrowedObject<'a> for PyBytes {
730 fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
731 PyBytesInner::try_from_borrowed_object(vm, obj).map(|x| x.into())
732 }
733}