1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
pub mod serde;
pub mod convert;
pub mod traits;
pub mod error_ext;
pub mod cast;

use std::fmt::{Display, Formatter};
use std::sync::Arc;
use teo_parser::r#type::Type;
use teo_teon::Value;
use teo_result::Error;
use crate::model;
use crate::pipeline::pipeline::Pipeline;
use crate::r#struct;
use teo_result::Result;
use crate::interface_enum_variant::InterfaceEnumVariant;
use crate::namespace::Namespace;
use crate::object::cast::TeonCast;

#[derive(Debug, Clone)]
pub struct Object {
    pub inner: Arc<ObjectInner>,
}

#[derive(Debug)]
pub enum ObjectInner {
    Teon(Value),
    ModelObject(model::Object),
    StructObject(r#struct::Object),
    Pipeline(Pipeline),
    InterfaceEnumVariant(InterfaceEnumVariant),
    Array(Vec<Object>),
}

impl AsRef<Object> for Object {

    fn as_ref(&self) -> &Object {
        self
    }
}

impl Object {

    pub fn is_teon(&self) -> bool {
        self.as_teon().is_some()
    }

    pub fn as_teon(&self) -> Option<&Value> {
        match self.inner.as_ref() {
            ObjectInner::Teon(v) => Some(v),
            _ => None,
        }
    }

    pub fn is_model_object(&self) -> bool {
        self.as_model_object().is_some()
    }

    pub fn as_model_object(&self) -> Option<&model::Object> {
        match self.inner.as_ref() {
            ObjectInner::ModelObject(v) => Some(v),
            _ => None,
        }
    }

    pub fn is_struct_object(&self) -> bool {
        self.as_struct_object().is_some()
    }

    pub fn as_struct_object(&self) -> Option<&r#struct::Object> {
        match self.inner.as_ref() {
            ObjectInner::StructObject(v) => Some(v),
            _ => None,
        }
    }

    pub fn is_pipeline(&self) -> bool {
        self.as_pipeline().is_some()
    }

    pub fn as_pipeline(&self) -> Option<&Pipeline> {
        match self.inner.as_ref() {
            ObjectInner::Pipeline(p) => Some(p),
            _ => None,
        }
    }

    pub fn is_interface_enum_variant(&self) -> bool {
        self.as_interface_enum_variant().is_some()
    }

    pub fn as_interface_enum_variant(&self) -> Option<&InterfaceEnumVariant> {
        match self.inner.as_ref() {
            ObjectInner::InterfaceEnumVariant(n) => Some(n),
            _ => None
        }
    }

    pub fn is_array(&self) -> bool {
        self.as_array().is_some()
    }

    pub fn as_array(&self) -> Option<&Vec<Object>> {
        match self.inner.as_ref() {
            ObjectInner::Array(a) => Some(a),
            _ => None,
        }
    }

    pub fn is_null(&self) -> bool {
        self.is_teon() && self.as_teon().unwrap().is_null()
    }

    pub fn try_into_err_prefix<'a, T: 'a, E>(&'a self, prefix: impl AsRef<str>) -> Result<T> where E: std::error::Error, T: TryFrom<&'a Object, Error = E> {
        let result: std::result::Result<T, E> = self.try_into();
        match result {
            Ok(t) => Ok(t),
            Err(e) => Err(Error::new(format!("{}: {e}", prefix.as_ref()))),
        }
    }

    pub fn try_into_err_message<'a, T: 'a, E>(&'a self, message: impl AsRef<str>) -> Result<T> where E: std::error::Error, T: TryFrom<&'a Object, Error = E> {
        let result: std::result::Result<T, E> = self.try_into();
        match result {
            Ok(t) => Ok(t),
            Err(_) => Err(Error::new(message.as_ref())),
        }
    }

    pub fn cast(&self, target: Option<&Type>, namespace: &Namespace) -> Self {
        if let Some(teon) = self.as_teon() {
            Object::from(teon.cast(target, namespace))
        } else {
            self.clone()
        }
    }
}

impl Display for Object {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self.inner.as_ref() {
            ObjectInner::Teon(teon) => Display::fmt(teon, f),
            ObjectInner::ModelObject(m) => Display::fmt(m, f),
            ObjectInner::StructObject(s) => Display::fmt(s, f),
            ObjectInner::Pipeline(p) => Display::fmt(p, f),
            ObjectInner::InterfaceEnumVariant(i) => Display::fmt(i, f),
            ObjectInner::Array(objects) => {
                f.write_str("[")?;
                objects.iter().map(|o| format!("{}", o)).collect::<Vec<String>>().join(", ");
                f.write_str("]")
            }
        }
    }
}