1use bitflags::bitflags;
3pub use bstr;
4use bstr::{BStr, BString};
5use num_bigint::BigInt;
6use num_complex::Complex;
7use num_derive::{FromPrimitive, ToPrimitive};
8use std::{
9 collections::{HashMap, HashSet},
10 convert::TryFrom,
11 fmt,
12 hash::{Hash, Hasher},
13 iter::FromIterator,
14 sync::{Arc, RwLock},
15};
16
17pub mod read;
18pub type ArcRwLock<T> = Arc<RwLock<T>>;
23
24#[derive(FromPrimitive, ToPrimitive, Debug, Copy, Clone)]
25#[repr(u8)]
26pub enum Type {
27 Null = b'0',
28 None = b'N',
29 False = b'F',
30 True = b'T',
31 StopIter = b'S',
32 Ellipsis = b'.',
33 Int = b'i',
34 Int64 = b'I',
35 Float = b'f',
36 BinaryFloat = b'g',
37 Complex = b'x',
38 BinaryComplex = b'y',
39 Long = b'l',
40 String = b's',
41 Interned = b't',
42 StringRef = b'R',
43 Tuple = b'(',
44 List = b'[',
45 Dict = b'{',
46 Code = b'c',
47 Unicode = b'u',
48 Unknown = b'?',
49 Set = b'<',
50 FrozenSet = b'>',
51 Bytes = 0x0,
53}
54impl Type {
55 const FLAG_REF: u8 = b'\x80';
56}
57
58pub(crate) struct Depth(Arc<()>);
59impl Depth {
60 const MAX: usize = 900;
61
62 #[must_use]
63 pub fn new() -> Self {
64 Self(Arc::new(()))
65 }
66
67 pub fn try_clone(&self) -> Option<Self> {
68 if Arc::strong_count(&self.0) > Self::MAX {
69 None
70 } else {
71 Some(Self(self.0.clone()))
72 }
73 }
74}
75impl fmt::Debug for Depth {
76 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
77 f.debug_tuple("Depth")
78 .field(&Arc::strong_count(&self.0))
79 .finish()
80 }
81}
82
83bitflags! {
84 pub struct CodeFlags: u32 {
85 const OPTIMIZED = 0x1;
86 const NEWLOCALS = 0x2;
87 const VARARGS = 0x4;
88 const VARKEYWORDS = 0x8;
89 const NESTED = 0x10;
90 const GENERATOR = 0x20;
91 const NOFREE = 0x40;
92 const COROUTINE = 0x80;
93 const ITERABLE_COROUTINE = 0x100;
94 const ASYNC_GENERATOR = 0x200;
95 const GENERATOR_ALLOWED = 0x1000;
97 const FUTURE_DIVISION = 0x2000;
98 const FUTURE_ABSOLUTE_IMPORT = 0x4000;
99 const FUTURE_WITH_STATEMENT = 0x8000;
100 const FUTURE_PRINT_FUNCTION = 0x10000;
101 const FUTURE_UNICODE_LITERALS = 0x20000;
102 const FUTURE_BARRY_AS_BDFL = 0x40000;
103 const FUTURE_GENERATOR_STOP = 0x80000;
104 #[allow(clippy::unreadable_literal)]
105 const FUTURE_ANNOTATIONS = 0x100000;
106 }
107}
108
109#[rustfmt::skip]
110#[derive(Clone, Debug)]
111pub struct Code {
112 pub argcount: u32,
113 pub nlocals: u32,
114 pub stacksize: u32,
115 pub flags: CodeFlags,
116 pub code: Arc<Vec<u8>>,
117 pub consts: Arc<Vec<Obj>>,
118 pub names: Vec<Arc<BString>>,
119 pub varnames: Vec<Arc<BString>>,
120 pub freevars: Vec<Arc<BString>>,
121 pub cellvars: Vec<Arc<BString>>,
122 pub filename: Arc<BString>,
123 pub name: Arc<BString>,
124 pub firstlineno: u32,
125 pub lnotab: Arc<Vec<u8>>,
126}
127
128#[rustfmt::skip]
129#[derive(Clone)]
130pub enum Obj {
131 None,
132 StopIteration,
133 Ellipsis,
134 Bool (bool),
135 Long (Arc<BigInt>),
136 Float (f64),
137 Complex (Complex<f64>),
138 Bytes (Arc<Vec<u8>>),
139 String (Arc<BString>),
140 Tuple (Arc<Vec<Obj>>),
141 List (ArcRwLock<Vec<Obj>>),
142 Dict (ArcRwLock<HashMap<ObjHashable, Obj>>),
143 Set (ArcRwLock<HashSet<ObjHashable>>),
144 FrozenSet(Arc<HashSet<ObjHashable>>),
145 Code (Arc<Code>),
146 }
148macro_rules! define_extract {
149 ($extract_fn:ident($variant:ident) -> ()) => {
150 define_extract! { $extract_fn -> () { $variant => () } }
151 };
152 ($extract_fn:ident($variant:ident) -> Arc<$ret:ty>) => {
153 define_extract! { $extract_fn -> Arc<$ret> { $variant(x) => x } }
154 };
155 ($extract_fn:ident($variant:ident) -> ArcRwLock<$ret:ty>) => {
156 define_extract! { $extract_fn -> ArcRwLock<$ret> { $variant(x) => x } }
157 };
158 ($extract_fn:ident($variant:ident) -> $ret:ty) => {
159 define_extract! { $extract_fn -> $ret { $variant(x) => x } }
160 };
161 ($extract_fn:ident -> $ret:ty { $variant:ident$(($($pat:pat),+))? => $expr:expr }) => {
162 pub fn $extract_fn(self) -> Result<$ret, Self> {
165 if let Self::$variant$(($($pat),+))? = self {
166 Ok($expr)
167 } else {
168 Err(self)
169 }
170 }
171 }
172}
173macro_rules! define_is {
174 ($is_fn:ident($variant:ident$(($($pat:pat),+))?)) => {
175 #[must_use]
178 pub fn $is_fn(&self) -> bool {
179 if let Self::$variant$(($($pat),+))? = self {
180 true
181 } else {
182 false
183 }
184 }
185 }
186}
187impl Obj {
188 define_extract! { extract_none (None) -> () }
189 define_extract! { extract_stop_iteration(StopIteration) -> () }
190 define_extract! { extract_bool (Bool) -> bool }
191 define_extract! { extract_long (Long) -> Arc<BigInt> }
192 define_extract! { extract_float (Float) -> f64 }
193 define_extract! { extract_bytes (String) -> Arc<BString> }
194 define_extract! { extract_string (String) -> Arc<BString> }
195 define_extract! { extract_tuple (Tuple) -> Arc<Vec<Self>> }
196 define_extract! { extract_list (List) -> ArcRwLock<Vec<Self>> }
197 define_extract! { extract_dict (Dict) -> ArcRwLock<HashMap<ObjHashable, Self>> }
198 define_extract! { extract_set (Set) -> ArcRwLock<HashSet<ObjHashable>> }
199 define_extract! { extract_frozenset (FrozenSet) -> Arc<HashSet<ObjHashable>> }
200 define_extract! { extract_code (Code) -> Arc<Code> }
201
202 define_is! { is_none (None) }
203 define_is! { is_stop_iteration(StopIteration) }
204 define_is! { is_bool (Bool(_)) }
205 define_is! { is_long (Long(_)) }
206 define_is! { is_float (Float(_)) }
207 define_is! { is_bytes (Bytes(_)) }
208 define_is! { is_string (String(_)) }
209 define_is! { is_tuple (Tuple(_)) }
210 define_is! { is_list (List(_)) }
211 define_is! { is_dict (Dict(_)) }
212 define_is! { is_set (Set(_)) }
213 define_is! { is_frozenset (FrozenSet(_)) }
214 define_is! { is_code (Code(_)) }
215}
216impl fmt::Debug for Obj {
230 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
231 match self {
232 Self::None => write!(f, "None"),
233 Self::StopIteration => write!(f, "StopIteration"),
234 Self::Ellipsis => write!(f, "Ellipsis"),
235 Self::Bool(true) => write!(f, "True"),
236 Self::Bool(false) => write!(f, "False"),
237 Self::Long(x) => write!(f, "{}", x),
238 &Self::Float(x) => python_float_repr_full(f, x),
239 &Self::Complex(x) => python_complex_repr(f, x),
240 Self::Bytes(x) => python_bytes_repr(f, x),
241 Self::String(x) => python_string_repr(f, x.as_ref().as_ref()),
242 Self::Tuple(x) => python_tuple_repr(f, x),
243 Self::List(x) => f.debug_list().entries(x.read().unwrap().iter()).finish(),
244 Self::Dict(x) => f.debug_map().entries(x.read().unwrap().iter()).finish(),
245 Self::Set(x) => f.debug_set().entries(x.read().unwrap().iter()).finish(),
246 Self::FrozenSet(x) => python_frozenset_repr(f, x),
247 Self::Code(x) => python_code_repr(f, x),
248 }
249 }
250}
251
252impl TryFrom<&ObjHashable> for Obj {
253 type Error = ObjHashable;
254
255 fn try_from(orig: &ObjHashable) -> Result<Self, ObjHashable> {
256 match orig {
257 ObjHashable::None => Ok(Self::None),
258 ObjHashable::StopIteration => Ok(Self::StopIteration),
259 ObjHashable::Ellipsis => Ok(Self::Ellipsis),
260 ObjHashable::Bool(x) => Ok(Self::Bool(*x)),
261 ObjHashable::Long(x) => Ok(Self::Long(Arc::clone(x))),
262 ObjHashable::Float(x) => Ok(Self::Float(x.0)),
263 ObjHashable::Complex(Complex { re, im }) => Ok(Self::Complex(Complex {
264 re: re.0,
265 im: im.0,
266 })),
267 ObjHashable::String(x) => Ok(Self::String(Arc::clone(x))),
268 ObjHashable::Tuple(x) => Ok(Self::Tuple(Arc::new(
269 x.iter()
270 .map(Self::try_from)
271 .collect::<Result<Vec<Self>, ObjHashable>>()?,
272 ))),
273 ObjHashable::FrozenSet(x) => Ok(Self::FrozenSet(Arc::new(
274 x.0.iter().cloned().collect::<HashSet<ObjHashable>>(),
275 ))),
276 }
277 }
278}
279
280impl Obj {
281 pub fn typ(&self) -> Type {
282 match self {
283 Self::None => Type::None,
284 Self::StopIteration => Type::StopIter,
285 Self::Ellipsis => Type::Ellipsis,
286 Self::Bool(true) => Type::True,
287 Self::Bool(false) => Type::False,
288 Self::Long(x) => Type::Long,
289 &Self::Float(x) => Type::Float,
290 &Self::Complex(x) => Type::Complex,
291 Self::Bytes(x) => Type::Bytes,
292 Self::String(x) => Type::String,
293 Self::Tuple(x) => Type::Tuple,
294 Self::List(x) => Type::List,
295 Self::Dict(x) => Type::Dict,
296 Self::Set(x) => Type::Set,
297 Self::FrozenSet(x) => Type::FrozenSet,
298 Self::Code(x) => Type::Code,
299 }
300 }
301}
302
303fn python_float_repr_full(f: &mut fmt::Formatter, x: f64) -> fmt::Result {
304 python_float_repr_core(f, x)?;
305 if x.fract() == 0. {
306 write!(f, ".0")?;
307 };
308 Ok(())
309}
310fn python_float_repr_core(f: &mut fmt::Formatter, x: f64) -> fmt::Result {
311 if x.is_nan() {
312 write!(f, "float('nan')")
313 } else if x.is_infinite() {
314 if x.is_sign_positive() {
315 write!(f, "float('inf')")
316 } else {
317 write!(f, "-float('inf')")
318 }
319 } else {
320 if x.is_sign_negative() {
322 write!(f, "-")?;
323 }
324 write!(f, "{}", x.abs())
325 }
326}
327fn python_complex_repr(f: &mut fmt::Formatter, x: Complex<f64>) -> fmt::Result {
328 if x.re == 0. && x.re.is_sign_positive() {
329 python_float_repr_core(f, x.im)?;
330 write!(f, "j")?;
331 } else {
332 write!(f, "(")?;
333 python_float_repr_core(f, x.re)?;
334 if x.im >= 0. || x.im.is_nan() {
335 write!(f, "+")?;
336 }
337 python_float_repr_core(f, x.im)?;
338 write!(f, "j)")?;
339 };
340 Ok(())
341}
342fn python_bytes_repr(f: &mut fmt::Formatter, x: &[u8]) -> fmt::Result {
343 write!(f, "b\"")?;
344 for &byte in x.iter() {
345 match byte {
346 b'\t' => write!(f, "\\t")?,
347 b'\n' => write!(f, "\\n")?,
348 b'\r' => write!(f, "\\r")?,
349 b'\'' | b'"' | b'\\' => write!(f, "\\{}", char::from(byte))?,
350 b' '..=b'~' => write!(f, "{}", char::from(byte))?,
351 _ => write!(f, "\\x{:02x}", byte)?,
352 }
353 }
354 write!(f, "\"")?;
355 Ok(())
356}
357fn python_string_repr(f: &mut fmt::Formatter, x: &BStr) -> fmt::Result {
358 let original = format!("{:?}", x);
359 let mut last_end = 0;
360 for (start, _) in original.match_indices("\\u{") {
362 f.write_str(&original[last_end..start])?;
363 let len = original[start..].find('}').ok_or(fmt::Error)? + 1;
364 let end = start + len;
365 match len - 4 {
366 0..=2 => write!(f, "\\x{:0>2}", &original[start + 3..end - 1])?,
367 3..=4 => write!(f, "\\u{:0>4}", &original[start + 3..end - 1])?,
368 5..=8 => write!(f, "\\U{:0>8}", &original[start + 3..end - 1])?,
369 _ => panic!("Internal error: length of unicode escape = {} > 8", len),
370 }
371 last_end = end;
372 }
373 f.write_str(&original[last_end..])?;
374 Ok(())
375}
376fn python_tuple_repr(f: &mut fmt::Formatter, x: &[Obj]) -> fmt::Result {
377 if x.is_empty() {
378 f.write_str("()") } else {
380 let mut debug_tuple = f.debug_tuple("");
381 for o in x.iter() {
382 debug_tuple.field(&o);
383 }
384 debug_tuple.finish()
385 }
386}
387fn python_frozenset_repr(f: &mut fmt::Formatter, x: &HashSet<ObjHashable>) -> fmt::Result {
388 f.write_str("frozenset(")?;
389 if !x.is_empty() {
390 f.debug_set().entries(x.iter()).finish()?;
391 }
392 f.write_str(")")?;
393 Ok(())
394}
395fn python_code_repr(f: &mut fmt::Formatter, x: &Code) -> fmt::Result {
396 write!(f, "code(argcount={:?}, nlocals={:?}, stacksize={:?}, flags={:?}, code={:?}, consts={:?}, names={:?}, varnames={:?}, freevars={:?}, cellvars={:?}, filename={:?}, name={:?}, firstlineno={:?}, lnotab=bytes({:?}))", x.argcount, x.nlocals, x.stacksize, x.flags, Obj::Bytes(Arc::clone(&x.code)), x.consts, x.names, x.varnames, x.freevars, x.cellvars, x.filename, x.name, x.firstlineno, &x.lnotab)
397}
398#[derive(Clone, Debug)]
401pub struct HashF64(f64);
402impl PartialEq for HashF64 {
403 fn eq(&self, other: &Self) -> bool {
404 self.0 == other.0 || (self.0.is_nan() && other.0.is_nan())
405 }
406}
407impl Eq for HashF64 {}
408impl Hash for HashF64 {
409 fn hash<H: Hasher>(&self, state: &mut H) {
410 if self.0.is_nan() {
411 state.write_u8(0);
413 } else if self.0 == 0.0 {
414 state.write_u8(1);
416 } else {
417 state.write_u64(self.0.to_bits()); }
419 }
420}
421
422#[derive(Debug)]
423pub struct HashableHashSet<T>(HashSet<T>);
424impl<T> Hash for HashableHashSet<T>
425where
426 T: Hash,
427{
428 fn hash<H: Hasher>(&self, state: &mut H) {
429 let mut xor: u64 = 0;
430 let hasher = std::collections::hash_map::DefaultHasher::new();
431 for value in &self.0 {
432 let mut hasher_clone = hasher.clone();
433 value.hash(&mut hasher_clone);
434 xor ^= hasher_clone.finish();
435 }
436 state.write_u64(xor);
437 }
438}
439impl<T> PartialEq for HashableHashSet<T>
440where
441 T: Eq + Hash,
442{
443 fn eq(&self, other: &Self) -> bool {
444 self.0 == other.0
445 }
446}
447impl<T> Eq for HashableHashSet<T> where T: Eq + Hash {}
448impl<T> FromIterator<T> for HashableHashSet<T>
449where
450 T: Eq + Hash,
451{
452 fn from_iter<I>(iter: I) -> Self
453 where
454 I: IntoIterator<Item = T>,
455 {
456 Self(iter.into_iter().collect())
457 }
458}
459
460#[derive(PartialEq, Eq, Hash, Clone)]
461pub enum ObjHashable {
462 None,
463 StopIteration,
464 Ellipsis,
465 Bool(bool),
466 Long(Arc<BigInt>),
467 Float(HashF64),
468 Complex(Complex<HashF64>),
469 String(Arc<BString>),
470 Tuple(Arc<Vec<ObjHashable>>),
471 FrozenSet(Arc<HashableHashSet<ObjHashable>>),
472 }
474impl TryFrom<&Obj> for ObjHashable {
475 type Error = Obj;
476
477 fn try_from(orig: &Obj) -> Result<Self, Obj> {
478 match orig {
479 Obj::None => Ok(Self::None),
480 Obj::StopIteration => Ok(Self::StopIteration),
481 Obj::Ellipsis => Ok(Self::Ellipsis),
482 Obj::Bool(x) => Ok(Self::Bool(*x)),
483 Obj::Long(x) => Ok(Self::Long(Arc::clone(x))),
484 Obj::Float(x) => Ok(Self::Float(HashF64(*x))),
485 Obj::Complex(Complex { re, im }) => Ok(Self::Complex(Complex {
486 re: HashF64(*re),
487 im: HashF64(*im),
488 })),
489 Obj::String(x) => Ok(Self::String(Arc::clone(x))),
490 Obj::Tuple(x) => Ok(Self::Tuple(Arc::new(
491 x.iter()
492 .map(Self::try_from)
493 .collect::<Result<Vec<Self>, Obj>>()?,
494 ))),
495 Obj::FrozenSet(x) => Ok(Self::FrozenSet(Arc::new(
496 x.iter().cloned().collect::<HashableHashSet<Self>>(),
497 ))),
498 x => Err(x.clone()),
499 }
500 }
501}
502impl fmt::Debug for ObjHashable {
503 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
504 match self {
505 Self::None => write!(f, "None"),
506 Self::StopIteration => write!(f, "StopIteration"),
507 Self::Ellipsis => write!(f, "Ellipsis"),
508 Self::Bool(true) => write!(f, "True"),
509 Self::Bool(false) => write!(f, "False"),
510 Self::Long(x) => write!(f, "{}", x),
511 Self::Float(x) => python_float_repr_full(f, x.0),
512 Self::Complex(x) => python_complex_repr(
513 f,
514 Complex {
515 re: x.re.0,
516 im: x.im.0,
517 },
518 ),
519 Self::String(x) => python_string_repr(f, x.as_ref().as_ref()),
520 Self::Tuple(x) => python_tuple_hashable_repr(f, x),
521 Self::FrozenSet(x) => python_frozenset_repr(f, &x.0),
522 }
523 }
524}
525fn python_tuple_hashable_repr(f: &mut fmt::Formatter, x: &[ObjHashable]) -> fmt::Result {
526 if x.is_empty() {
527 f.write_str("()") } else {
529 let mut debug_tuple = f.debug_tuple("");
530 for o in x.iter() {
531 debug_tuple.field(&o);
532 }
533 debug_tuple.finish()
534 }
535}
536
537#[cfg(test)]
538mod test {
539 use super::{Code, CodeFlags, Obj, ObjHashable};
540 use bstr::{BString, ByteSlice};
541 use num_bigint::BigInt;
542 use num_complex::Complex;
543 use std::{
544 collections::{HashMap, HashSet},
545 sync::{Arc, RwLock},
546 };
547
548 #[test]
549 fn test_debug_repr() {
550 assert_eq!(format!("{:?}", Obj::None), "None");
551 assert_eq!(format!("{:?}", Obj::StopIteration), "StopIteration");
552 assert_eq!(format!("{:?}", Obj::Ellipsis), "Ellipsis");
553 assert_eq!(format!("{:?}", Obj::Bool(true)), "True");
554 assert_eq!(format!("{:?}", Obj::Bool(false)), "False");
555 assert_eq!(
556 format!("{:?}", Obj::Long(Arc::new(BigInt::from(-123)))),
557 "-123"
558 );
559 assert_eq!(format!("{:?}", Obj::Tuple(Arc::new(vec![]))), "()");
560 assert_eq!(
561 format!("{:?}", Obj::Tuple(Arc::new(vec![Obj::Bool(true)]))),
562 "(True,)"
563 );
564 assert_eq!(
565 format!(
566 "{:?}",
567 Obj::Tuple(Arc::new(vec![Obj::Bool(true), Obj::None]))
568 ),
569 "(True, None)"
570 );
571 assert_eq!(
572 format!(
573 "{:?}",
574 Obj::List(Arc::new(RwLock::new(vec![Obj::Bool(true)])))
575 ),
576 "[True]"
577 );
578 assert_eq!(
579 format!(
580 "{:?}",
581 Obj::Dict(Arc::new(RwLock::new(
582 vec![(
583 ObjHashable::Bool(true),
584 Obj::Bytes(Arc::new(Vec::from(b"a" as &[u8])))
585 )]
586 .into_iter()
587 .collect::<HashMap<_, _>>()
588 )))
589 ),
590 "{True: b\"a\"}"
591 );
592 assert_eq!(
593 format!(
594 "{:?}",
595 Obj::Set(Arc::new(RwLock::new(
596 vec![ObjHashable::Bool(true)]
597 .into_iter()
598 .collect::<HashSet<_>>()
599 )))
600 ),
601 "{True}"
602 );
603 assert_eq!(
604 format!(
605 "{:?}",
606 Obj::FrozenSet(Arc::new(
607 vec![ObjHashable::Bool(true)]
608 .into_iter()
609 .collect::<HashSet<_>>()
610 ))
611 ),
612 "frozenset({True})"
613 );
614 assert_eq!(format!("{:?}", Obj::Code(Arc::new(Code {
615 argcount: 0,
616 nlocals: 3,
617 stacksize: 4,
618 flags: CodeFlags::NESTED | CodeFlags::COROUTINE,
619 code: Arc::new(Vec::from(b"abc" as &[u8])),
620 consts: Arc::new(vec![Obj::Bool(true)]),
621 names: vec![],
622 varnames: vec![Arc::new(BString::from("a"))],
623 freevars: vec![Arc::new(BString::from("b")), Arc::new(BString::from("c"))],
624 cellvars: vec![Arc::new(BString::from("de"))],
625 filename: Arc::new(BString::from("xyz.py")),
626 name: Arc::new(BString::from("fgh")),
627 firstlineno: 5,
628 lnotab: Arc::new(vec![255, 0, 45, 127, 0, 73]),
629 }))), "code(argcount=0, nlocals=3, stacksize=4, flags=NESTED | COROUTINE, code=b\"abc\", consts=[True], names=[], varnames=[\"a\"], freevars=[\"b\", \"c\"], cellvars=[\"de\"], filename=\"xyz.py\", name=\"fgh\", firstlineno=5, lnotab=bytes([255, 0, 45, 127, 0, 73]))");
630 }
631
632 #[test]
633 fn test_float_debug_repr() {
634 assert_eq!(format!("{:?}", Obj::Float(1.23)), "1.23");
635 assert_eq!(format!("{:?}", Obj::Float(f64::NAN)), "float('nan')");
636 assert_eq!(format!("{:?}", Obj::Float(f64::INFINITY)), "float('inf')");
637 assert_eq!(format!("{:?}", Obj::Float(-f64::INFINITY)), "-float('inf')");
638 assert_eq!(format!("{:?}", Obj::Float(0.0)), "0.0");
639 assert_eq!(format!("{:?}", Obj::Float(-0.0)), "-0.0");
640 }
641
642 #[test]
643 fn test_complex_debug_repr() {
644 assert_eq!(
645 format!("{:?}", Obj::Complex(Complex { re: 2., im: 1. })),
646 "(2+1j)"
647 );
648 assert_eq!(
649 format!("{:?}", Obj::Complex(Complex { re: 0., im: 1. })),
650 "1j"
651 );
652 assert_eq!(
653 format!("{:?}", Obj::Complex(Complex { re: 2., im: 0. })),
654 "(2+0j)"
655 );
656 assert_eq!(
657 format!("{:?}", Obj::Complex(Complex { re: 0., im: 0. })),
658 "0j"
659 );
660 assert_eq!(
661 format!("{:?}", Obj::Complex(Complex { re: -2., im: 1. })),
662 "(-2+1j)"
663 );
664 assert_eq!(
665 format!("{:?}", Obj::Complex(Complex { re: -2., im: 0. })),
666 "(-2+0j)"
667 );
668 assert_eq!(
669 format!("{:?}", Obj::Complex(Complex { re: 2., im: -1. })),
670 "(2-1j)"
671 );
672 assert_eq!(
673 format!("{:?}", Obj::Complex(Complex { re: 0., im: -1. })),
674 "-1j"
675 );
676 assert_eq!(
677 format!("{:?}", Obj::Complex(Complex { re: -2., im: -1. })),
678 "(-2-1j)"
679 );
680 assert_eq!(
681 format!("{:?}", Obj::Complex(Complex { re: 0., im: -1. })),
682 "-1j"
683 );
684 assert_eq!(
685 format!("{:?}", Obj::Complex(Complex { re: -2., im: 0. })),
686 "(-2+0j)"
687 );
688 assert_eq!(
689 format!("{:?}", Obj::Complex(Complex { re: -0., im: 1. })),
690 "(-0+1j)"
691 );
692 assert_eq!(
693 format!("{:?}", Obj::Complex(Complex { re: -0., im: -1. })),
694 "(-0-1j)"
695 );
696 }
697
698 #[test]
699 fn test_bytes_string_debug_repr() {
700 assert_eq!(format!("{:?}", Obj::Bytes(Arc::new(Vec::from(
701 b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe" as &[u8]
702 )))),
703 "b\"\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\\\"#$%&\\\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x7f\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\""
704 );
705 assert_eq!(format!("{:?}", Obj::String(Arc::new(BString::from(
706 "\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f")))),
707 "\"\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\\\"#$%&\\\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x7f\"");
708 }
709}
710
711mod utils {
712 use num_bigint::{BigUint, Sign};
713 use num_traits::Zero;
714 use std::cmp::Ordering;
715
716 #[allow(clippy::cast_possible_truncation)]
718 pub fn biguint_from_pylong_digits(digits: &[u16]) -> BigUint {
719 if digits.is_empty() {
720 return BigUint::zero();
721 };
722 assert!(digits[digits.len() - 1] != 0);
723 let mut accum: u64 = 0;
724 let mut accumbits: u8 = 0;
725 let mut p = Vec::<u32>::new();
726 for (i, &thisdigit) in digits.iter().enumerate() {
727 accum |= u64::from(thisdigit) << accumbits;
728 accumbits += if i == digits.len() - 1 {
729 16 - (thisdigit.leading_zeros() as u8)
730 } else {
731 15
732 };
733
734 while accumbits >= 32 {
736 p.push(accum as u32);
737 accumbits -= 32;
738 accum >>= 32;
739 }
740 }
741 assert!(accumbits < 32);
742 if accumbits > 0 {
743 p.push(accum as u32);
744 }
745 BigUint::new(p)
746 }
747
748 pub fn sign_of<T: Ord + Zero>(x: &T) -> Sign {
749 match x.cmp(&T::zero()) {
750 Ordering::Less => Sign::Minus,
751 Ordering::Equal => Sign::NoSign,
752 Ordering::Greater => Sign::Plus,
753 }
754 }
755
756 #[cfg(test)]
757 mod test {
758 use super::biguint_from_pylong_digits;
759 use num_bigint::BigUint;
760
761 #[allow(clippy::inconsistent_digit_grouping)]
762 #[test]
763 fn test_biguint_from_pylong_digits() {
764 assert_eq!(
765 biguint_from_pylong_digits(&[
766 0b000_1101_1100_0100,
767 0b110_1101_0010_0100,
768 0b001_0000_1001_1101
769 ]),
770 BigUint::from(0b001_0000_1001_1101_110_1101_0010_0100_000_1101_1100_0100_u64)
771 );
772 }
773 }
774}