use std::{
cell::Cell,
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
sync::{
atomic::{AtomicUsize, Ordering},
Arc, Mutex, RwLock,
},
};
pub use pyo3_special_method_derive_macro::*;
pub static ELLIPSIS_CHAR_N: AtomicUsize = AtomicUsize::new(100);
pub trait PyDebug {
fn fmt_debug(&self) -> String;
}
pub trait PyDisplay {
fn fmt_display(&self) -> String;
}
#[macro_export]
macro_rules! pydebug_pydisplay {
($t:ty) => {
impl PyDebug for $t {
fn fmt_debug(&self) -> String {
format!("{self:?}")
}
}
impl PyDisplay for $t {
fn fmt_display(&self) -> String {
format!("{self:?}")
}
}
};
}
pydebug_pydisplay!(u8);
pydebug_pydisplay!(u16);
pydebug_pydisplay!(u32);
pydebug_pydisplay!(u64);
pydebug_pydisplay!(u128);
pydebug_pydisplay!(usize);
pydebug_pydisplay!(i8);
pydebug_pydisplay!(i16);
pydebug_pydisplay!(i32);
pydebug_pydisplay!(i64);
pydebug_pydisplay!(i128);
pydebug_pydisplay!(f32);
pydebug_pydisplay!(f64);
pydebug_pydisplay!(bool);
pydebug_pydisplay!(String);
pydebug_pydisplay!(&str);
pydebug_pydisplay!(char);
fn do_format(start: char, end: char, iter: impl Iterator<Item = String>) -> String {
let n = ELLIPSIS_CHAR_N.load(Ordering::Relaxed);
let mut res = "".to_string();
for x in iter {
if res.len() + 2 + x.len() <= n {
res += &format!("{x}, ");
} else {
res += "..., ";
break;
}
}
format!("{start}{}{end}", &res[..res.len() - 2])
}
impl<T: PyDebug> PyDebug for &[T] {
fn fmt_debug(&self) -> String {
do_format('[', ']', self.iter().map(|x| x.fmt_debug()))
}
}
impl<T: PyDisplay> PyDisplay for &[T] {
fn fmt_display(&self) -> String {
do_format('[', ']', self.iter().map(|x| x.fmt_display()))
}
}
impl<T: PyDebug> PyDebug for Vec<T> {
fn fmt_debug(&self) -> String {
do_format('[', ']', self.iter().map(|x| x.fmt_debug()))
}
}
impl<T: PyDisplay> PyDisplay for Vec<T> {
fn fmt_display(&self) -> String {
do_format('[', ']', self.iter().map(|x| x.fmt_display()))
}
}
impl<T: PyDebug> PyDebug for Option<T> {
fn fmt_debug(&self) -> String {
match self {
Some(x) => x.fmt_debug(),
None => "None".to_string(),
}
}
}
impl<T: PyDisplay> PyDisplay for Option<T> {
fn fmt_display(&self) -> String {
match self {
Some(x) => x.fmt_display(),
None => "None".to_string(),
}
}
}
impl<T: PyDebug> PyDebug for RwLock<T> {
fn fmt_debug(&self) -> String {
match self.read() {
Ok(x) => x.fmt_debug(),
Err(_) => "None".to_string(),
}
}
}
impl<T: PyDisplay> PyDisplay for RwLock<T> {
fn fmt_display(&self) -> String {
match self.read() {
Ok(x) => x.fmt_display(),
Err(_) => "None".to_string(),
}
}
}
impl<T: PyDebug> PyDebug for Mutex<T> {
fn fmt_debug(&self) -> String {
match self.lock() {
Ok(x) => x.fmt_debug(),
Err(_) => "None".to_string(),
}
}
}
impl<T: PyDisplay> PyDisplay for Mutex<T> {
fn fmt_display(&self) -> String {
match self.lock() {
Ok(x) => x.fmt_display(),
Err(_) => "None".to_string(),
}
}
}
impl<T: PyDebug> PyDebug for Arc<RwLock<T>> {
fn fmt_debug(&self) -> String {
match self.read() {
Ok(x) => x.fmt_debug(),
Err(_) => "None".to_string(),
}
}
}
impl<T: PyDisplay> PyDisplay for Arc<RwLock<T>> {
fn fmt_display(&self) -> String {
match self.read() {
Ok(x) => x.fmt_display(),
Err(_) => "None".to_string(),
}
}
}
impl<T: PyDebug> PyDebug for Arc<Mutex<T>> {
fn fmt_debug(&self) -> String {
match self.lock() {
Ok(x) => x.fmt_debug(),
Err(_) => "None".to_string(),
}
}
}
impl<T: PyDisplay> PyDisplay for Arc<Mutex<T>> {
fn fmt_display(&self) -> String {
match self.lock() {
Ok(x) => x.fmt_display(),
Err(_) => "None".to_string(),
}
}
}
impl<T: PyDebug + Copy> PyDebug for Cell<T> {
fn fmt_debug(&self) -> String {
self.get().fmt_debug()
}
}
impl<T: PyDisplay + Copy> PyDisplay for Cell<T> {
fn fmt_display(&self) -> String {
self.get().fmt_display()
}
}
impl<K: PyDebug, V: PyDebug> PyDebug for HashMap<K, V> {
fn fmt_debug(&self) -> String {
do_format(
'{',
'}',
self.iter()
.map(|(k, v)| format!("{}: {}", k.fmt_debug(), v.fmt_debug())),
)
}
}
impl<K: PyDisplay, V: PyDisplay> PyDisplay for HashMap<K, V> {
fn fmt_display(&self) -> String {
do_format(
'{',
'}',
self.iter()
.map(|(k, v)| format!("{}: {}", k.fmt_display(), v.fmt_display())),
)
}
}
impl<V: PyDebug> PyDebug for HashSet<V> {
fn fmt_debug(&self) -> String {
do_format('{', '}', self.iter().map(|v| v.fmt_debug()))
}
}
impl<V: PyDisplay> PyDisplay for HashSet<V> {
fn fmt_display(&self) -> String {
do_format('{', '}', self.iter().map(|v| v.fmt_display()))
}
}
impl<K: PyDebug, V: PyDebug> PyDebug for BTreeMap<K, V> {
fn fmt_debug(&self) -> String {
do_format(
'{',
'}',
self.iter()
.map(|(k, v)| format!("{}: {}", k.fmt_debug(), v.fmt_debug())),
)
}
}
impl<K: PyDisplay, V: PyDisplay> PyDisplay for BTreeMap<K, V> {
fn fmt_display(&self) -> String {
do_format(
'{',
'}',
self.iter()
.map(|(k, v)| format!("{}: {}", k.fmt_display(), v.fmt_display())),
)
}
}
impl<V: PyDebug> PyDebug for BTreeSet<V> {
fn fmt_debug(&self) -> String {
do_format('{', '}', self.iter().map(|v| v.fmt_debug()))
}
}
impl<V: PyDisplay> PyDisplay for BTreeSet<V> {
fn fmt_display(&self) -> String {
do_format('{', '}', self.iter().map(|v| v.fmt_display()))
}
}