rtea/
object.rs

1use std::ffi::CStr;
2use std::ffi::CString;
3use std::ffi::c_void;
4use std::fmt::Display;
5use std::os::raw::c_char;
6
7use crate::Interpreter;
8use crate::TclStatus;
9use crate::tcl::*;
10
11/// A wrapper for [Tcl objects](https://www.tcl.tk/man/tcl/TclLib/Object.html).
12///
13/// WIP
14#[repr(C)]
15#[derive(Debug)]
16pub struct RawObject {
17    pub(crate) ref_count: usize,
18    pub bytes: *mut c_char,
19    pub length: usize,
20    pub obj_type: *const ObjectType,
21    pub ptr1: *mut c_void,
22    pub ptr2: *mut c_void,
23}
24
25impl RawObject {
26    pub fn wrap(obj: *mut RawObject) -> Object {
27        unsafe { 
28            INCR_REF_COUNT
29            .expect("module must have been initialized")
30            (obj)
31        };
32        Object { obj: obj }
33    }
34}
35
36#[derive(Debug)]
37pub struct Object {
38    pub obj: *mut RawObject,
39}
40
41impl Object {
42    pub fn new() -> Object {
43        unsafe { RawObject::wrap(NEW_OBJ.expect("module must have been initialized")()) }
44    }
45
46    pub fn new_string(s: &str) -> Object {
47        let cstr = CString::new(s).expect("Unexpected NulError!");
48        unsafe {
49            RawObject::wrap(NEW_STRING_OBJ.expect("module must have been initialized")(
50                cstr.as_ptr() as *const i8,
51                cstr.as_bytes().len() as usize,
52            ))
53        }
54    }
55
56    pub fn set_string(&self, s: &str) {
57        let cstr = CString::new(s).expect("unexpected NulError!");
58        unsafe {
59            SET_STRING_OBJ.expect("module must have been initialized")(
60                self.obj,
61                cstr.as_ptr() as *const i8,
62                cstr.as_bytes().len() as usize,
63            );
64        }
65    }
66
67    /// Gets the string associated with the Tcl object.
68    pub fn get_string(&self) -> &str {
69        unsafe {
70            CStr::from_ptr(GET_STRING.expect("module must have been initialized")(
71                self.obj,
72            ))
73            .to_str()
74            .expect("TCL guarantees strings are valid UTF-8")
75        }
76    }
77
78    /// Gets the Tcl ObjType Name
79    pub fn get_type_name(&self) -> &str {
80        let raw_obj = unsafe { &*self.obj };
81        if raw_obj.obj_type.is_null() {
82            "string"
83        } else {
84            unsafe {
85                let obj_type = &*raw_obj.obj_type;
86                CStr::from_ptr(obj_type.name as *const i8)
87                    .to_str()
88                    .expect("TCL guarantees string are valid UTF-8")
89            }
90        }
91    }
92}
93
94impl Drop for Object {
95    fn drop(&mut self) {
96        unsafe { DECR_REF_COUNT.expect("module must have been initialized")(self.obj) }
97    }
98}
99
100impl Display for Object {
101    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
102        unsafe {
103            let o_type = (*self.obj).obj_type;
104            if (*self.obj).bytes.is_null()
105                && !o_type.is_null()
106                && o_type.as_ref().unwrap().update_string_proc.is_some()
107            {
108                let update_fn = o_type.as_ref().unwrap().update_string_proc.unwrap();
109                update_fn(self.obj);
110            } else if (*self.obj).bytes.is_null() {
111                panic!("invalid string representation and no update function");
112            }
113
114            write!(f, "{}", CStr::from_ptr((*self.obj).bytes).to_str().unwrap())
115        }
116    }
117}
118
119/// A wrapper for [Tcl object types](https://www.tcl.tk/man/tcl/TclLib/ObjectType.html).
120///
121/// WIP
122#[repr(C)]
123#[derive(Debug)]
124pub struct ObjectType {
125    pub name: *const u8,
126    pub free_internal_rep_proc: Option<extern "C" fn(*mut RawObject)>,
127    pub dup_internal_rep_proc: extern "C" fn(*const RawObject, *mut RawObject),
128    pub update_string_proc: Option<extern "C" fn(*mut RawObject)>,
129    pub set_from_any_proc: Option<extern "C" fn(*const Interpreter, *mut RawObject) -> TclStatus>,
130}
131
132unsafe impl Sync for ObjectType {}
133
134pub trait TclObjectType: Clone + Display {
135    fn from_object(obj: &Object) -> Option<&Self>;
136
137    fn into_object(self) -> Object;
138
139    fn type_name() -> &'static str;
140
141    fn tcl_type() -> &'static ObjectType;
142
143    fn as_string(&self) -> String {
144        format!("{}", self)
145    }
146
147    fn convert(obj: Object) -> Result<Object, Object> {
148        Err(obj)
149    }
150}