use crate::model::DataType;
use crate::model::format::LevelFormatAble;
use crate::model::{FNameStr, FValueStr};
use crate::model::Value;
use crate::traits::AsValueRef;
use serde::Deserialize;
use serde::Serialize;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
use std::sync::Arc;
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct Field<T> {
pub meta: DataType,
pub name: FNameStr,
pub value: T,
}
pub trait ValueRef<T> {
fn value_ref(&self) -> &T;
}
impl<T> ValueRef<T> for Field<T> {
fn value_ref(&self) -> &T {
&self.value
}
}
impl<T> From<Field<T>> for Field<Rc<T>> {
fn from(other: Field<T>) -> Self {
let value = Rc::<T>::from(other.value);
Self {
meta: other.meta,
name: other.name,
value,
}
}
}
impl<T> From<Field<T>> for Field<Arc<T>> {
fn from(other: Field<T>) -> Self {
let value = Arc::<T>::from(other.value);
Self {
meta: other.meta,
name: other.name,
value,
}
}
}
impl<T> Field<T> {
pub fn new<S: Into<FNameStr>, V: Into<T>>(meta: DataType, name: S, value: V) -> Self {
Self {
meta,
name: name.into(),
value: value.into(),
}
}
pub fn new_opt(meta: DataType, name: Option<FNameStr>, value: T) -> Self {
let name = name.unwrap_or_else(|| FNameStr::from(String::from(&meta)));
Field { meta, name, value }
}
pub fn get_name(&self) -> &str {
self.name.as_str()
}
pub fn clone_name(&self) -> String {
self.name.as_str().to_string()
}
pub fn get_meta(&self) -> &DataType {
&self.meta
}
pub fn set_name<S: Into<FNameStr>>(&mut self, name: S) {
self.name = name.into()
}
}
impl Field<Value> {
pub fn from_shared_chars<S: Into<FNameStr>>(name: S, val: FValueStr) -> Self {
Self::new(DataType::Chars, name.into(), Value::Chars(val))
}
pub fn get_chars(&self) -> Option<&str> {
self.value.as_str()
}
pub fn get_chars_mut(&mut self) -> Option<&mut FValueStr> {
self.value.ensure_owned_chars()
}
}
impl<T> Field<T>
where
T: AsValueRef<Value>,
{
pub fn get_value(&self) -> &Value {
self.value.as_value_ref()
}
pub fn get_value_mut(&mut self) -> &mut Value {
self.value.as_value_mutref()
}
}
impl<T> LevelFormatAble for Field<T>
where
T: Display,
{
fn level_fmt(&self, f: &mut Formatter<'_>, level: usize) -> std::fmt::Result {
let meta: String = From::from(&self.meta);
writeln!(
f,
"{:width$}[{:<16}] {:<20} : {}",
"",
meta,
self.name,
self.value,
width = level * 6
)?;
Ok(())
}
}
impl<T> Display for Field<T>
where
T: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}({})", self.meta, self.value)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::model::{DataField, FValueStr};
#[test]
fn test_field_new() {
let field: Field<i64> = Field::new(DataType::Digit, "count", 42i64);
assert_eq!(field.meta, DataType::Digit);
assert_eq!(field.get_name(), "count");
assert_eq!(field.value, 42);
}
#[test]
fn test_field_new_with_string_conversion() {
let field: Field<String> = Field::new(DataType::Chars, String::from("key"), "value");
assert_eq!(field.get_name(), "key");
assert_eq!(field.value, "value");
}
#[test]
fn test_field_new_opt_with_name() {
let field: Field<i64> = Field::new_opt(DataType::Digit, Some("num".into()), 100);
assert_eq!(field.get_name(), "num");
assert_eq!(field.value, 100);
}
#[test]
fn test_field_new_opt_without_name() {
let field: Field<i64> = Field::new_opt(DataType::Digit, None, 50);
assert_eq!(field.get_name(), "digit");
assert_eq!(field.value, 50);
}
#[test]
fn test_field_get_name() {
let field: Field<i64> = Field::new(DataType::Digit, "test_name", 1);
assert_eq!(field.get_name(), "test_name");
}
#[test]
fn test_field_clone_name() {
let field: Field<i64> = Field::new(DataType::Digit, "original", 1);
let cloned = field.clone_name();
assert_eq!(cloned, "original");
assert_eq!(cloned, field.get_name());
}
#[test]
fn test_field_get_meta() {
let field: Field<i64> = Field::new(DataType::Float, "val", 1);
assert_eq!(field.get_meta(), &DataType::Float);
}
#[test]
fn test_field_set_name() {
let mut field: Field<i64> = Field::new(DataType::Digit, "old_name", 1);
field.set_name("new_name");
assert_eq!(field.get_name(), "new_name");
}
#[test]
fn test_value_ref_trait() {
let field: Field<i64> = Field::new(DataType::Digit, "num", 42);
assert_eq!(field.value_ref(), &42);
}
#[test]
fn test_field_get_value() {
let field: DataField = Field::new(DataType::Digit, "num", Value::Digit(99));
assert_eq!(field.get_value(), &Value::Digit(99));
}
#[test]
fn test_field_get_value_mut() {
let mut field: DataField = Field::new(DataType::Digit, "num", Value::Digit(10));
*field.get_value_mut() = Value::Digit(20);
assert_eq!(field.get_value(), &Value::Digit(20));
}
#[test]
fn test_field_from_shared_chars() {
let s = FValueStr::from("hello");
let field: DataField = Field::from_shared_chars("msg", s.clone());
assert_eq!(field.get_name(), "msg");
assert_eq!(field.get_meta(), &DataType::Chars);
assert!(matches!(field.value, Value::Chars(_)));
assert_eq!(field.get_chars(), Some("hello"));
}
#[test]
fn test_field_get_chars_mut() {
let s = FValueStr::from("foo");
let mut field: DataField = Field::from_shared_chars("msg", s);
{
let value = field.get_chars_mut().expect("mutable");
*value = FValueStr::from(format!("{}-bar", value.as_str()));
}
assert!(matches!(field.value, Value::Chars(_)));
assert_eq!(field.get_chars(), Some("foo-bar"));
}
#[test]
fn test_field_to_rc() {
let field: Field<i64> = Field::new(DataType::Digit, "num", 42);
let rc_field: Field<Rc<i64>> = field.into();
assert_eq!(rc_field.get_name(), "num");
assert_eq!(rc_field.meta, DataType::Digit);
assert_eq!(*rc_field.value, 42);
}
#[test]
fn test_field_to_arc() {
let field: Field<String> = Field::new(DataType::Chars, "msg", String::from("hello"));
let arc_field: Field<Arc<String>> = field.into();
assert_eq!(arc_field.get_name(), "msg");
assert_eq!(arc_field.meta, DataType::Chars);
assert_eq!(*arc_field.value, "hello");
}
#[test]
fn test_field_display() {
let field: Field<i64> = Field::new(DataType::Digit, "count", 42);
let display = format!("{}", field);
assert!(display.contains("digit"));
assert!(display.contains("42"));
}
#[test]
fn test_field_display_chars() {
let field: Field<String> = Field::new(DataType::Chars, "msg", String::from("hello"));
let display = format!("{}", field);
assert!(display.contains("chars"));
assert!(display.contains("hello"));
}
#[test]
fn test_level_format_able() {
let field: Field<i64> = Field::new(DataType::Digit, "level_test", 123);
let mut output = String::new();
use std::fmt::Write;
let _ = write!(output, "{}", field);
assert!(output.contains("digit"));
assert!(output.contains("123"));
}
#[test]
fn test_field_clone() {
let field: Field<i64> = Field::new(DataType::Digit, "num", 42);
let cloned = field.clone();
assert_eq!(field, cloned);
assert_eq!(cloned.get_name(), "num");
assert_eq!(cloned.value, 42);
}
#[test]
fn test_field_partial_eq() {
let field1: Field<i64> = Field::new(DataType::Digit, "num", 42);
let field2: Field<i64> = Field::new(DataType::Digit, "num", 42);
let field3: Field<i64> = Field::new(DataType::Digit, "num", 99);
assert_eq!(field1, field2);
assert_ne!(field1, field3);
}
#[test]
fn test_field_serde_roundtrip() {
let field: Field<i64> = Field::new(DataType::Digit, "serde_test", 123);
let json = serde_json::to_string(&field).unwrap();
let parsed: Field<i64> = serde_json::from_str(&json).unwrap();
assert_eq!(field, parsed);
}
#[test]
fn test_field_serde_with_string() {
let field: Field<String> = Field::new(DataType::Chars, "msg", String::from("test"));
let json = serde_json::to_string(&field).unwrap();
let parsed: Field<String> = serde_json::from_str(&json).unwrap();
assert_eq!(field.name, parsed.name);
assert_eq!(field.value, parsed.value);
}
}