use crate::core::{
entities::{
properties::prop::{Prop, PropArray, PropUntagged},
GID,
},
storage::{
arc_str::ArcStr,
timeindex::{AsTime, EventTime},
},
};
use bigdecimal::BigDecimal;
use chrono::{DateTime, NaiveDateTime, TimeZone};
use indexmap::IndexMap;
use itertools::Itertools;
use pyo3::{prelude::PyAnyMethods, Bound, Py, PyAny, Python};
use std::{collections::HashMap, error::Error, ops::Deref, sync::Arc};
pub fn iterator_repr<I: Iterator<Item = V>, V: Repr>(iter: I) -> String {
let values: Vec<String> = iter.take(11).map(|v| v.repr()).collect();
if values.len() < 11 {
values.join(", ")
} else {
values[0..10].join(", ") + ", ..."
}
}
pub fn iterator_dict_repr<I: Iterator<Item = (K, V)>, K: Repr, V: Repr>(iter: I) -> String {
let values: Vec<String> = iter
.take(11)
.map(|(k, v)| format!("{}: {}", k.repr(), v.repr()))
.collect();
if values.len() < 11 {
values.join(", ")
} else {
values[0..10].join(", ") + ", ..."
}
}
pub struct StructReprBuilder {
value: String,
has_fields: bool,
}
impl StructReprBuilder {
pub fn new(name: &str) -> Self {
Self {
value: name.to_owned() + "(",
has_fields: false,
}
}
fn add_field_sep(&mut self) {
if self.has_fields {
self.value.push_str(", ");
} else {
self.has_fields = true;
}
}
pub fn add_field<V: Repr>(mut self, name: &str, value: V) -> Self {
self.add_field_sep();
self.value.push_str(name);
self.value.push('=');
self.value.push_str(&value.repr());
self
}
pub fn add_fields_from_iter<I: Iterator<Item = (K, V)>, K: Repr, V: Repr>(
mut self,
iter: I,
) -> Self {
self.add_field_sep();
self.value.push_str(&iterator_dict_repr(iter));
self
}
pub fn finish(self) -> String {
let mut value = self.value;
value.push(')');
value
}
}
pub trait Repr {
fn repr(&self) -> String;
}
impl Repr for PropUntagged {
fn repr(&self) -> String {
self.0.repr()
}
}
impl Repr for Prop {
fn repr(&self) -> String {
match &self {
Prop::Str(v) => v.repr(),
Prop::Bool(v) => v.repr(),
Prop::I64(v) => v.repr(),
Prop::U8(v) => v.repr(),
Prop::U16(v) => v.repr(),
Prop::U64(v) => v.repr(),
Prop::F64(v) => v.repr(),
Prop::DTime(v) => v.repr(),
Prop::NDTime(v) => v.repr(),
Prop::I32(v) => v.repr(),
Prop::U32(v) => v.repr(),
Prop::F32(v) => v.repr(),
Prop::List(v) => v.repr(),
Prop::Map(v) => v.repr(),
Prop::Decimal(v) => v.repr(),
}
}
}
impl<T: Repr, const N: usize> Repr for [T; N] {
fn repr(&self) -> String {
self.as_slice().repr()
}
}
impl Repr for Py<PyAny> {
fn repr(&self) -> String {
Python::attach(|py| Repr::repr(self.bind(py)))
}
}
impl<'py> Repr for Bound<'py, PyAny> {
fn repr(&self) -> String {
let repr = PyAnyMethods::repr(self);
match repr {
Ok(repr) => repr.to_string(),
Err(_) => "<unknown>".to_string(),
}
}
}
impl Repr for GID {
fn repr(&self) -> String {
match self {
GID::U64(v) => v.repr(),
GID::Str(v) => v.repr(),
}
}
}
impl Repr for bool {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for u32 {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for u8 {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for u16 {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for u64 {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for i32 {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for i64 {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for usize {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for f32 {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for f64 {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for String {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for ArcStr {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for &str {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for NaiveDateTime {
fn repr(&self) -> String {
self.to_string()
}
}
impl Repr for EventTime {
fn repr(&self) -> String {
let mut builder = StructReprBuilder::new("EventTime").add_field("t", self.t());
if let Ok(dt) = self.dt() {
builder = builder.add_field("dt", dt)
}
builder.add_field("event_id", self.i()).finish()
}
}
impl Repr for BigDecimal {
fn repr(&self) -> String {
self.to_string()
}
}
impl<T: TimeZone> Repr for DateTime<T> {
fn repr(&self) -> String {
self.to_rfc3339()
}
}
impl<T: Repr> Repr for Option<T> {
fn repr(&self) -> String {
match &self {
Some(v) => v.repr(),
None => "None".to_string(),
}
}
}
impl<T: Repr, E: Error> Repr for Result<T, E> {
fn repr(&self) -> String {
match self {
Ok(v) => v.repr(),
Err(e) => e.to_string(),
}
}
}
impl<T: Repr> Repr for &[T] {
fn repr(&self) -> String {
let repr = self.iter().map(|v| v.repr()).join(", ");
format!("[{}]", repr)
}
}
impl<T: Repr> Repr for Vec<T> {
fn repr(&self) -> String {
self.deref().repr()
}
}
impl Repr for PropArray {
fn repr(&self) -> String {
let repr = self.iter().map(|v| v.repr()).join(", ");
format!("[{}]", repr)
}
}
impl<T: Repr> Repr for Arc<[T]> {
fn repr(&self) -> String {
self.deref().repr()
}
}
impl<K: Repr, V: Repr, S> Repr for HashMap<K, V, S> {
fn repr(&self) -> String {
let repr = self
.iter()
.map(|(k, v)| format!("{}: {}", k.repr(), v.repr()))
.join(", ");
format!("{{{}}}", repr)
}
}
impl<K: Repr, V: Repr, S> Repr for IndexMap<K, V, S> {
fn repr(&self) -> String {
let repr = self
.iter()
.map(|(k, v)| format!("{}: {}", k.repr(), v.repr()))
.join(", ");
format!("{{{}}}", repr)
}
}
impl<S: Repr, T: Repr> Repr for (S, T) {
fn repr(&self) -> String {
format!("({}, {})", self.0.repr(), self.1.repr())
}
}
impl<S: Repr, T: Repr, U: Repr> Repr for (S, T, U) {
fn repr(&self) -> String {
format!("({}, {}, {})", self.0.repr(), self.1.repr(), self.2.repr())
}
}
impl<S: Repr, T: Repr, U: Repr, V: Repr> Repr for (S, T, U, V) {
fn repr(&self) -> String {
format!(
"({}, {}, {}, {})",
self.0.repr(),
self.1.repr(),
self.2.repr(),
self.3.repr()
)
}
}
impl<R: Repr> Repr for &R {
fn repr(&self) -> String {
R::repr(self)
}
}
#[cfg(test)]
mod repr_tests {
use super::*;
#[test]
fn test_option_some() {
let v = Some(1);
assert_eq!(v.repr(), "1")
}
#[test]
fn test_option_none() {
let v: Option<String> = None;
assert_eq!(v.repr(), "None")
}
#[test]
fn test_int() {
let v = 1;
assert_eq!(v.repr(), "1")
}
#[test]
fn test_int_ref() {
let v = 1;
assert_eq!(v.repr(), "1")
}
#[test]
fn test_string_ref() {
let v = "test";
assert_eq!(v.repr(), "test")
}
}