1use std::{cell::RefCell, ffi::c_void, fs::File, path::PathBuf};
2
3use crate::{compilation::message_and_exit, context::RynaContext, integer_ext::to_i64, mut_cell::MutCell, types::{Type, ARR_ID, ARR_IT_ID, BOOL, BOOL_ID, FILE, FILE_ID, FLOAT, FLOAT_ID, INT, INT_ID, LIB, LIB_FUNC, LIB_FUNC_ID, LIB_ID, PTR, PTR_ID, STR, STR_ID}, ARR_IT_OF, ARR_OF};
4use libloading::{Library, Symbol};
5use malachite::Integer;
6use rclite::Rc;
7use rynaffi::{FFIArgs, FFIReturn, FFIValue, RynaFFIFunction};
8use serde::{Deserialize, Serialize};
9
10type DataBlock = Rc<MutCell<ObjectBlock>>;
11
12#[derive(Clone, PartialEq, Debug)]
19pub struct RynaPointer {
20 pub ptr: *const c_void
21}
22
23impl RynaPointer {
24 pub fn new(ptr: *const c_void) -> RynaPointer {
25 RynaPointer { ptr }
26 }
27}
28
29#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
30pub struct RynaArray {
31 pub elements: Vec<Object>,
32 pub elem_type: Box<Type>
33}
34
35#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
36pub struct RynaTuple {
37 pub elements: Vec<Object>,
38 pub elem_types: Vec<Type>
39}
40
41#[derive(Clone, PartialEq, Debug)]
42pub struct RynaArrayIt {
43 pub pos: usize,
44 pub block: DataBlock,
45 pub it_type: Box<Type>,
46 pub c_type: Box<Type>
47}
48
49impl RynaArrayIt {
50 pub fn get_container_ref(&self) -> Object {
51 Object {
52 inner: self.block.clone()
53 }.get_ref()
54 }
55}
56
57#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
58pub struct RynaLambda {
59 pub loc: usize,
60 pub captures: Vec<Object>,
61 pub args_type: Box<Type>,
62 pub ret_type: Box<Type>
63}
64
65#[derive(Clone, Debug)]
66pub struct RynaFile {
67 pub path: PathBuf,
68 pub file: Option<Rc<RefCell<File>>>
69}
70
71impl PartialEq for RynaFile {
72 fn eq(&self, other: &Self) -> bool {
73 match (&self.file, &other.file) {
74 (None, None) => self.path == other.path,
75 (Some(a), Some(b)) => self.path == other.path && Rc::ptr_eq(a, b),
76
77 _ => false
78 }
79 }
80}
81
82impl RynaFile {
83 pub fn is_open(&self) -> bool {
84 self.file.is_some()
85 }
86
87 pub fn close(&mut self) -> Result<(), String> {
88 if !self.is_open() {
89 return Err(format!("File at {} is already closed", self.path.to_str().unwrap()));
90 }
91
92 self.file = None;
93
94 Ok(())
95 }
96
97 pub fn open(&mut self, read: bool, write: bool, append: bool) -> Result<(), String> {
98 if self.is_open() {
99 return Err(format!("File at {} is already open", self.path.to_str().unwrap()));
100 }
101
102 let file = std::fs::OpenOptions::new()
103 .create(write || append)
104 .read(read)
105 .write(write)
106 .append(append)
107 .open(&self.path);
108
109 match file {
110 Ok(inner) => {
111 self.file = Some(Rc::new(RefCell::new(inner)));
112 Ok(())
113 },
114
115 Err(_) => Err(format!("Unable to open file file at {}", self.path.to_str().unwrap()))
116 }
117 }
118
119 pub fn exists(&self) -> Result<bool, String> {
120 Ok(self.path.is_file())
121 }
122
123 pub fn delete(&mut self) -> Result<bool, String> {
124 if !self.is_open() {
125 return Err(format!("File at {} is closed", self.path.to_str().unwrap()));
126 }
127
128 if std::fs::remove_file(&self.path).is_ok() {
129 self.file = None;
130 Ok(true)
131
132 } else {
133 Ok(false)
134 }
135 }
136}
137
138#[derive(Clone, Debug)]
139pub struct RynaLibrary {
140 pub path: PathBuf,
141 pub lib: Rc<Library>
142}
143
144impl PartialEq for RynaLibrary {
145 fn eq(&self, other: &Self) -> bool {
146 return self.path == other.path;
147 }
148}
149
150impl RynaLibrary {
151 pub fn new(path: &String, lib: Library) -> RynaLibrary {
152 RynaLibrary {
153 path: PathBuf::from(path),
154 lib: Rc::new(lib)
155 }
156 }
157
158 pub fn get_function(&self, name: &String) -> Result<RynaLibraryFunction, String> {
159 let sym: Symbol<RynaFFIFunction> = unsafe { self.lib.get(name.as_bytes()).map_err(|_| format!("Unable to open symbol {name}"))? };
160
161 Ok(RynaLibraryFunction {
162 path: format!("{}:{}", self.path.to_str().unwrap(), name),
163 func: *sym
164 })
165 }
166}
167
168#[derive(Clone, Debug)]
169pub struct RynaLibraryFunction {
170 pub path: String,
171 pub func: RynaFFIFunction
172}
173
174impl PartialEq for RynaLibraryFunction {
175 fn eq(&self, other: &Self) -> bool {
176 return self.path == other.path;
177 }
178}
179
180impl RynaLibraryFunction {
181 pub fn call(&self, args: &[Object]) -> Result<Object, String> {
182 let args_l = args.iter().map(Object::to_ffi).collect::<Result<Vec<_>, _>>()?;
183 let args_struct = FFIArgs::new(&args_l);
184 let mut out = FFIReturn::Void;
185
186 unsafe { (self.func)(&args_struct, &mut out); }
187
188 match out {
189 FFIReturn::Value(v) => match v {
190 FFIValue::Int(i) => Ok(Object::new(Integer::from(i))),
191 FFIValue::Float(i) => Ok(Object::new(i)),
192 FFIValue::Pointer(p) => Ok(Object::new(RynaPointer::new(p))),
193 },
194 FFIReturn::Void => Ok(Object::empty()),
195 }
196 }
197}
198
199#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
200pub struct TypeInstance {
201 pub id: usize,
202 pub params: Vec<Type>,
203 pub attributes: Vec<Object>
204}
205
206#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
207pub enum ObjectBlock {
208 #[default]
209 NoValue, Empty,
212 Int(malachite::Integer),
213 Float(f64),
214 Str(String),
215 Bool(bool),
216
217 Tuple(RynaTuple),
218 Array(RynaArray),
219
220 #[serde(skip)]
221 ArrayIter(RynaArrayIt),
222
223 Lambda(RynaLambda),
224
225 #[serde(skip)]
226 Pointer(RynaPointer),
227
228 #[serde(skip)]
229 File(RynaFile),
230
231 #[serde(skip)]
232 Library(RynaLibrary),
233
234 #[serde(skip)]
235 LibraryFunction(RynaLibraryFunction),
236
237 Instance(TypeInstance),
238
239 #[serde(skip)]
240 Ref(DataBlock),
241 #[serde(skip)]
242 Mut(DataBlock),
243}
244
245impl Eq for ObjectBlock {}
246
247impl ObjectBlock {
248 #[inline(always)]
249 pub fn to_obj(self) -> Object {
250 Object { inner: Rc::new(MutCell::new(self)) }
251 }
252
253 pub fn get_type_id(&self) -> usize {
254 match self {
255 ObjectBlock::NoValue => message_and_exit("Accessing moved object".into()),
256 ObjectBlock::Empty => 0,
257 ObjectBlock::Int(_) => INT_ID,
258 ObjectBlock::Float(_) => FLOAT_ID,
259 ObjectBlock::Str(_) => STR_ID,
260 ObjectBlock::Bool(_) => BOOL_ID,
261 ObjectBlock::Tuple(_) => 0,
262 ObjectBlock::Array(_) => ARR_ID,
263 ObjectBlock::ArrayIter(_) => ARR_IT_ID,
264 ObjectBlock::Lambda(_) => 0,
265 ObjectBlock::Pointer(_) => PTR_ID,
266 ObjectBlock::File(_) => FILE_ID,
267 ObjectBlock::Library(_) => LIB_ID,
268 ObjectBlock::LibraryFunction(_) => LIB_FUNC_ID,
269 ObjectBlock::Instance(i) => i.id,
270 ObjectBlock::Ref(_) => 0,
271 ObjectBlock::Mut(_) => 0,
272 }
273 }
274
275 pub fn get_type(&self) -> Type {
276 return match self {
277 ObjectBlock::NoValue => message_and_exit("Accessing moved object".into()),
278 ObjectBlock::Empty => Type::Empty,
279 ObjectBlock::Int(_) => INT,
280 ObjectBlock::Float(_) => FLOAT,
281 ObjectBlock::Str(_) => STR,
282 ObjectBlock::Bool(_) => BOOL,
283 ObjectBlock::Tuple(t) => Type::And(t.elem_types.clone()),
284 ObjectBlock::Array(a) => ARR_OF!(*a.elem_type.clone()),
285 ObjectBlock::ArrayIter(i) => ARR_IT_OF!(*i.c_type.clone(), *i.it_type.clone()),
286 ObjectBlock::Lambda(l) => Type::Function(l.args_type.clone(), l.ret_type.clone()),
287 ObjectBlock::Pointer(_) => PTR,
288 ObjectBlock::File(_) => FILE,
289 ObjectBlock::Library(_) => LIB,
290 ObjectBlock::LibraryFunction(_) => LIB_FUNC,
291 ObjectBlock::Instance(i) => if i.params.is_empty() { Type::Basic(i.id) } else { Type::Template(i.id, i.params.clone()) },
292 ObjectBlock::Ref(r) => Type::Ref(Box::new(r.borrow().get_type())),
293 ObjectBlock::Mut(r) => Type::MutRef(Box::new(r.borrow().get_type())),
294 };
295 }
296
297 pub fn is_moved(&self) -> bool {
298 matches!(self, ObjectBlock::NoValue)
299 }
300
301 pub fn get_inner<T>(&self) -> &T where ObjectBlock: Get<T> {
302 return Get::<T>::get(self);
303 }
304
305 pub fn mut_inner<T>(&mut self) -> &mut T where ObjectBlock: GetMut<T> {
306 return GetMut::<T>::get(self);
307 }
308
309 pub fn dereference(&self) -> &DataBlock {
310 if let ObjectBlock::Ref(n) | ObjectBlock::Mut(n) = self {
311 return n;
312 }
313
314 unreachable!();
315 }
316
317 pub fn assign_ref(&mut self, other: ObjectBlock, ctx: &RynaContext) -> Result<(), String> {
318 self.dereference().borrow_mut().assign(other, ctx)
319 }
320
321 pub fn assign(&mut self, other: ObjectBlock, ctx: &RynaContext) -> Result<(), String> {
322 use ObjectBlock::*;
323
324 match (self, other) {
325 (Int(a), Int(b)) => *a = b,
326 (Float(a), Float(b)) => *a = b,
327 (Str(a), Str(b)) => *a = b,
328 (Bool(a), Bool(b)) => *a = b,
329 (Array(a), Array(b)) if a.elem_type == b.elem_type => *a = b,
330 (ArrayIter(a), ArrayIter(b)) if a.it_type == b.it_type => *a = b,
331 (Lambda(a), Lambda(b)) if a.args_type == b.args_type && a.ret_type == b.ret_type => *a = b,
332 (Instance(a), Instance(b)) if a.id == b.id && a.params == b.params => *a = b,
333 (Tuple(a), Tuple(b)) if a.elem_types == b.elem_types => *a = b,
334
335 (a, b) => return Err(format!(
336 "Unable to assign value of type {} to block of type {}",
337 b.get_type().get_name(ctx),
338 a.get_type().get_name(ctx)
339 ))
340 };
341
342 Ok(())
343 }
344
345 pub fn deep_clone(&self) -> Self {
346 return match self {
347 ObjectBlock::NoValue => message_and_exit("Accessing moved object".into()),
348
349 ObjectBlock::Empty => ObjectBlock::Empty,
350 ObjectBlock::Int(n) => ObjectBlock::Int(n.clone()),
351 ObjectBlock::Float(n) => ObjectBlock::Float(*n),
352 ObjectBlock::Str(s) => ObjectBlock::Str(s.clone()),
353 ObjectBlock::Bool(b) => ObjectBlock::Bool(*b),
354 ObjectBlock::Tuple(t) => ObjectBlock::Tuple(RynaTuple {
355 elements: t.elements.iter().map(Object::deep_clone).collect(),
356 elem_types: t.elem_types.clone()
357 }),
358 ObjectBlock::Array(a) => ObjectBlock::Array(RynaArray {
359 elements: a.elements.iter().map(Object::deep_clone).collect(),
360 elem_type: a.elem_type.clone()
361 }),
362 ObjectBlock::ArrayIter(i) => ObjectBlock::ArrayIter(RynaArrayIt {
363 pos: i.pos,
364 block: i.block.clone(),
365 it_type: i.it_type.clone(),
366 c_type: i.c_type.clone()
367 }),
368 ObjectBlock::Lambda(l) => ObjectBlock::Lambda(RynaLambda {
369 loc: l.loc,
370 captures: l.captures.iter().map(Object::deep_clone).collect(),
371 args_type: l.args_type.clone(),
372 ret_type: l.ret_type.clone()
373 }),
374 ObjectBlock::Pointer(p) => ObjectBlock::Pointer(p.clone()),
375 ObjectBlock::File(f) => ObjectBlock::File(f.clone()),
376 ObjectBlock::Library(l) => ObjectBlock::Library(l.clone()),
377 ObjectBlock::LibraryFunction(f) => ObjectBlock::LibraryFunction(f.clone()),
378 ObjectBlock::Instance(i) => ObjectBlock::Instance(TypeInstance {
379 id: i.id,
380 params: i.params.clone(),
381 attributes: i.attributes.iter().map(Object::deep_clone).collect()
382 }),
383 ObjectBlock::Ref(r) => ObjectBlock::Ref(r.clone()),
384 ObjectBlock::Mut(r) => ObjectBlock::Mut(r.clone()),
385 }
386 }
387}
388
389#[derive(Clone, PartialEq, Eq, Debug)]
390pub struct Object {
391 pub inner: DataBlock
392}
393
394impl Serialize for Object {
395 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
396 where
397 S: serde::Serializer {
398 self.inner.borrow().serialize(serializer)
399 }
400}
401
402impl<'de> Deserialize<'de> for Object {
403 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
404 where
405 D: serde::Deserializer<'de> {
406 let inner = ObjectBlock::deserialize(deserializer)?;
407 Ok(inner.to_obj())
408 }
409}
410
411impl Object {
412 pub fn new<T: RynaData>(data: T) -> Self {
413 data.data().to_obj()
414 }
415
416 pub fn get_ptr(&self) -> *mut ObjectBlock {
417 (*self.inner).as_ptr()
418 }
419
420 pub fn arr(elements: Vec<Object>, elem_type: Type) -> Self {
421 ObjectBlock::Array(RynaArray { elements, elem_type: Box::new(elem_type) }).to_obj()
422 }
423
424 pub fn arr_it(c_type: Type, it_type: Type, block: DataBlock, pos: usize) -> Self {
425 ObjectBlock::ArrayIter(RynaArrayIt { pos, block, c_type: Box::new(c_type), it_type: Box::new(it_type) }).to_obj()
426 }
427
428 pub fn lambda(loc: usize, captures: Vec<Object>, args_type: Type, ret_type: Type) -> Self {
429 ObjectBlock::Lambda(RynaLambda { loc, captures, args_type: Box::new(args_type), ret_type: Box::new(ret_type) }).to_obj()
430 }
431
432 pub fn tuple(elements: Vec<Object>, elem_types: Vec<Type>) -> Self {
433 ObjectBlock::Tuple(RynaTuple { elements, elem_types }).to_obj()
434 }
435
436 pub fn file(path: PathBuf) -> Self {
437 ObjectBlock::File(RynaFile { path, file: None }).to_obj()
438 }
439
440 pub fn instance(attributes: Vec<Object>, params: Vec<Type>, id: usize) -> Self {
441 ObjectBlock::Instance(TypeInstance { params, attributes, id }).to_obj()
442 }
443
444 pub fn get<T>(&self) -> &T where ObjectBlock: Get<T> {
445 Get::<T>::get(self.inner.borrow())
446 }
447
448 #[allow(clippy::should_implement_trait)]
449 pub fn deref<T>(&self) -> &mut T where ObjectBlock: Deref<T> + GetMut<T> {
450 Deref::<T>::deref(self.inner.borrow())
451 }
452
453 pub fn ref_count(&self) -> usize {
454 Rc::strong_count(&self.inner)
455 }
456
457 pub fn deref_ref_count(&self) -> usize {
458 match &mut *self.inner.borrow_mut() {
459 ObjectBlock::Mut(i) | ObjectBlock::Ref(i) => Rc::strong_count(&i),
460 _ => unreachable!()
461 }
462 }
463
464 pub fn is_moved(&self) -> bool {
465 return self.inner.borrow().is_moved();
466 }
467
468 pub fn is_moved_deref(&self) -> bool {
469 match &mut *self.inner.borrow_mut() {
470 ObjectBlock::Mut(i) | ObjectBlock::Ref(i) => i.borrow().is_moved(),
471 _ => unreachable!()
472 }
473 }
474
475 pub fn to_ffi(&self) -> Result<FFIValue, String> {
476 match self.inner.borrow() {
477 ObjectBlock::NoValue => message_and_exit("Accessing moved object".into()),
478
479 ObjectBlock::Bool(v) => Ok(FFIValue::Int(if *v { 1 } else { 0 })),
480 ObjectBlock::Int(i) => Ok(FFIValue::Int(to_i64(&i))),
481 ObjectBlock::Float(i) => Ok(FFIValue::Float(*i)),
482 ObjectBlock::Str(s) => Ok(FFIValue::Pointer((s as *const String) as *const c_void)),
483 ObjectBlock::Pointer(p) => Ok(FFIValue::Pointer(p.ptr)),
484
485 _ => Err(format!("Unable to tranfer object to FFI layer"))
486 }
487 }
488
489 pub fn move_contents(&self) -> Object {
493 let res = ObjectBlock::default().to_obj();
494
495 match &mut *self.inner.borrow_mut() {
496 ObjectBlock::Mut(i) => std::mem::swap(&mut *i.borrow_mut(), &mut *res.inner.borrow_mut()),
497 _ => unreachable!()
498 };
499
500 res
501 }
502
503 pub fn move_contents_if_ref(&self) -> Object {
504 let res = ObjectBlock::default().to_obj();
505
506 match &mut *self.inner.borrow_mut() {
507 ObjectBlock::Mut(i) => std::mem::swap(&mut *i.borrow_mut(), &mut *res.inner.borrow_mut()),
508 i => std::mem::swap(i, &mut *res.inner.borrow_mut())
509 };
510
511 res
512 }
513
514 pub fn unsafe_move_contents(&self) -> Object {
515 let res = ObjectBlock::default().to_obj();
516
517 match &mut *self.inner.borrow_mut() {
518 ObjectBlock::Ref(i) => std::mem::swap(&mut *i.borrow_mut(), &mut *res.inner.borrow_mut()),
519 _ => unreachable!()
520 };
521
522 res
523 }
524
525 pub fn swap_contents(&self, other: &Object) {
526 match (&mut *self.inner.borrow_mut(), &mut *other.inner.borrow_mut()) {
527 (ObjectBlock::Mut(a), ObjectBlock::Mut(b)) => std::mem::swap(&mut *a.borrow_mut(), &mut *b.borrow_mut()),
528 _ => unreachable!()
529 };
530 }
531
532 pub fn drop_contents(&self) {
533 match &mut *self.inner.borrow_mut() {
534 ObjectBlock::Mut(i) => std::mem::take(&mut *i.borrow_mut()),
535 _ => unreachable!()
536 };
537 }
538
539 pub fn assign(&self, other_obj: Object, ctx: &RynaContext) -> Result<(), String> {
540 match Rc::try_unwrap(other_obj.inner) {
541 Ok(inner) => self.inner.borrow_mut().assign_ref(inner.take(), ctx),
542 Err(inner) => self.inner.borrow_mut().assign_ref(inner.borrow().clone(), ctx)
543 }
544 }
545
546 pub fn assign_direct(&self, other_obj: Object, ctx: &RynaContext) -> Result<(), String> {
547 match Rc::try_unwrap(other_obj.inner) {
548 Ok(inner) => self.inner.borrow_mut().assign(inner.take(), ctx),
549 Err(inner) => self.inner.borrow_mut().assign(inner.borrow().clone(), ctx)
550 }
551 }
552
553 pub fn from_inner(inner: DataBlock) -> Self {
554 Object { inner }
555 }
556
557 pub fn no_value() -> Object {
558 ObjectBlock::NoValue.to_obj()
559 }
560
561 pub fn empty() -> Object {
562 ObjectBlock::Empty.to_obj()
563 }
564
565 pub fn get_ref(&self) -> Object {
566 return match self.inner.borrow() {
567 ObjectBlock::Ref(i) |
568 ObjectBlock::Mut(i) => ObjectBlock::Ref(i.clone()).to_obj(),
569
570 _ => ObjectBlock::Ref(self.inner.clone()).to_obj()
571 }
572 }
573
574 pub fn get_var(&self) -> Object {
575 return match self.inner.borrow() {
576 ObjectBlock::Ref(i) => ObjectBlock::Ref(i.clone()).to_obj(),
577 ObjectBlock::Mut(i) => ObjectBlock::Mut(i.clone()).to_obj(),
578
579 _ => ObjectBlock::Mut(self.inner.clone()).to_obj()
580 }
581 }
582
583 pub fn get_mut(&self) -> Object {
584 return match self.inner.borrow() {
585 ObjectBlock::Ref(i) |
586 ObjectBlock::Mut(i) => ObjectBlock::Mut(i.clone()).to_obj(),
587
588 _ => ObjectBlock::Mut(self.inner.clone()).to_obj()
589 }
590 }
591
592 pub fn get_ref_nostack(&self) -> Object {
593 ObjectBlock::Ref(self.inner.clone()).to_obj()
594 }
595
596 pub fn get_mut_nostack(&self) -> Object {
597 ObjectBlock::Mut(self.inner.clone()).to_obj()
598 }
599
600 pub fn to_debug_string(&self) -> String {
601 format!("{:?}", self.inner.borrow())
602 }
603
604 pub fn deref_if_ref(&self) -> Object {
605 return match self.inner.borrow() {
606 ObjectBlock::Ref(i) |
607 ObjectBlock::Mut(i) => Object::from_inner(i.clone()),
608
609 _ => self.clone()
610 }
611 }
612
613 pub fn deref_deep_clone(&self) -> Object {
614 return match self.inner.borrow() {
615 ObjectBlock::Ref(i) |
616 ObjectBlock::Mut(i) => i.borrow().deep_clone().to_obj(),
617
618 obj => obj.deep_clone().to_obj()
619 }
620 }
621
622 pub fn deep_clone(&self) -> Object {
623 self.inner.borrow().deep_clone().to_obj()
624 }
625
626 pub fn get_type_id(&self) -> usize {
627 return self.inner.borrow().get_type_id();
628 }
629
630 pub fn get_type(&self) -> Type {
631 return self.inner.borrow().get_type();
632 }
633
634 pub fn deref_obj(&self) -> Object {
635 return match self.inner.borrow() {
636 ObjectBlock::Ref(r) | ObjectBlock::Mut(r) => Object::from_inner(r.clone()),
637 _ => unreachable!()
638 };
639 }
640}
641
642pub trait RynaData {
643 fn data(self) -> ObjectBlock;
644}
645
646pub trait Get<T> {
647 fn get(&self) -> &T;
648}
649
650pub trait GetMut<T> {
651 fn get(&mut self) -> &mut T;
652}
653
654pub trait Deref<T> {
655 #[allow(clippy::mut_from_ref)]
656 fn deref(&self) -> &mut T;
657}
658
659macro_rules! impl_ryna_data {
660 ($t: ty, $v: tt) => {
661 impl RynaData for $t {
662 #[inline(always)]
663 fn data(self) -> ObjectBlock {
664 return ObjectBlock::$v(self)
665 }
666 }
667
668 impl Get<$t> for ObjectBlock {
669 #[inline(always)]
670 fn get(&self) -> &$t {
671 if let ObjectBlock::$v(n) = self {
672 return n;
673 }
674
675 unreachable!("Unable to get {:?}", self);
676 }
677 }
678
679 impl GetMut<$t> for ObjectBlock {
680 #[inline(always)]
681 fn get(&mut self) -> &mut $t {
682 if let ObjectBlock::$v(n) = self {
683 return n;
684 }
685
686 unreachable!("Unable to get mut {:?}", self);
687 }
688 }
689
690 impl Deref<$t> for ObjectBlock {
691 #[inline(always)]
692 fn deref(&self) -> &mut $t {
693 return GetMut::<$t>::get(self.dereference().borrow_mut());
694 }
695 }
696 };
697}
698
699impl_ryna_data!(Integer, Int);
700impl_ryna_data!(f64, Float);
701impl_ryna_data!(String, Str);
702impl_ryna_data!(bool, Bool);
703impl_ryna_data!(TypeInstance, Instance);
704impl_ryna_data!(RynaArray, Array);
705impl_ryna_data!(RynaTuple, Tuple);
706impl_ryna_data!(RynaLambda, Lambda);
707impl_ryna_data!(RynaArrayIt, ArrayIter);
708impl_ryna_data!(RynaPointer, Pointer);
709impl_ryna_data!(RynaFile, File);
710impl_ryna_data!(RynaLibrary, Library);
711impl_ryna_data!(RynaLibraryFunction, LibraryFunction);
712
713#[cfg(test)]
720mod tests {
721 use crate::context::standard_ctx;
722 use malachite::Integer;
723 use crate::object::*;
724
725 #[test]
726 fn object_construction() {
727 let number = Object::new(Integer::from(10));
728
729 assert_eq!(*number.get::<Integer>(), Integer::from(10));
730
731 let string = Object::new(String::from("Test"));
732
733 assert_eq!(*string.get::<String>(), "Test".to_string());
734
735 assert_ne!(number.get_type_id(), string.get_type_id());
736 }
737
738 #[test]
739 fn references() {
740 let ctx = standard_ctx();
741
742 let number = Object::new(Integer::from(10));
743
744 assert_eq!(*number.get::<Integer>(), Integer::from(10));
745
746 let reference = number.get_mut();
747 let ref_of_ref = reference.get_ref();
748
749 assert_eq!(*reference.deref::<Integer>(), Integer::from(10));
750 assert_eq!(*ref_of_ref.deref::<Integer>(), Integer::from(10));
751
752 assert_ne!(number.get_ptr(), reference.get_ptr());
753 assert_ne!(number.get_ptr(), ref_of_ref.get_ptr());
754 assert_ne!(reference.get_ptr(), ref_of_ref.get_ptr());
755 assert_eq!(number.get_ptr(), (**reference.inner.borrow().dereference()).as_ptr());
756 assert_eq!(number.get_ptr(), (**ref_of_ref.inner.borrow().dereference()).as_ptr());
757
758 {
759 *reference.deref::<Integer>() += Integer::from(5);
760 }
761
762 assert_eq!(*number.get::<Integer>(), Integer::from(15));
763 assert_eq!(*reference.deref::<Integer>(), Integer::from(15));
764 assert_eq!(*ref_of_ref.deref::<Integer>(), Integer::from(15));
765
766 reference.assign(ObjectBlock::Int(Integer::from(20)).to_obj(), &ctx).unwrap();
767
768 assert_eq!(*number.get::<Integer>(), Integer::from(20));
769 assert_eq!(*reference.deref::<Integer>(), Integer::from(20));
770 assert_eq!(*ref_of_ref.deref::<Integer>(), Integer::from(20));
771 }
772
773 #[test]
774 fn value_moving() {
775 let number = Object::new(Integer::from(10));
776
777 assert_eq!(*number.get::<Integer>(), Integer::from(10));
778
779 let reference = number.get_mut();
780 let ref_of_ref = reference.get_mut();
781
782 assert_ne!(number.get_ptr(), reference.get_ptr());
783 assert_ne!(number.get_ptr(), ref_of_ref.get_ptr());
784 assert_ne!(reference.get_ptr(), ref_of_ref.get_ptr());
785 assert_eq!(number.get_ptr(), (**reference.inner.borrow().dereference()).as_ptr());
786 assert_eq!(number.get_ptr(), (**ref_of_ref.inner.borrow().dereference()).as_ptr());
787
788 assert_eq!(number.ref_count(), 3);
789
790 let number_2 = reference.move_contents();
791
792 assert!(number.is_moved());
793 assert!(reference.deref_obj().is_moved());
794 assert!(ref_of_ref.deref_obj().is_moved());
795 assert_eq!(number.ref_count(), 3);
796
797 assert!(!number_2.is_moved());
798 assert_eq!(number_2.ref_count(), 1);
799 assert_eq!(*number_2.get::<Integer>(), Integer::from(10));
800 }
801}