// Copyright 2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. /*! Task-local garbage-collected boxes The `Gc` type provides shared ownership of an immutable value. Destruction is not deterministic, and will occur some time between every `Gc` handle being gone and the end of the task. The garbage collector is task-local so `Gc` is not sendable. */ #[allow(experimental)]; use kinds::marker; use kinds::Send; use clone::{Clone, DeepClone}; use managed; /// Immutable garbage-collected pointer type #[lang="gc"] #[cfg(not(test))] #[experimental = "Gc is currently based on reference-counting and will not collect cycles until \ task annihilation. For now, cycles need to be broken manually by using `Rc` \ with a non-owning `Weak` pointer. A tracing garbage collector is planned."] pub struct Gc { priv ptr: @T, priv marker: marker::NoSend, } #[cfg(test)] pub struct Gc { priv ptr: @T, priv marker: marker::NoSend, } impl Gc { /// Construct a new garbage-collected box #[inline] pub fn new(value: T) -> Gc { Gc { ptr: @value, marker: marker::NoSend } } /// Borrow the value contained in the garbage-collected box #[inline] pub fn borrow<'r>(&'r self) -> &'r T { &*self.ptr } /// Determine if two garbage-collected boxes point to the same object #[inline] pub fn ptr_eq(&self, other: &Gc) -> bool { managed::ptr_eq(self.ptr, other.ptr) } } impl Clone for Gc { /// Clone the pointer only #[inline] fn clone(&self) -> Gc { Gc{ ptr: self.ptr, marker: marker::NoSend } } } /// An value that represents the task-local managed heap. /// /// Use this like `let foo = box(GC) Bar::new(...);` #[lang="managed_heap"] #[cfg(not(test))] pub static GC: () = (); #[cfg(test)] pub static GC: () = (); /// The `Send` bound restricts this to acyclic graphs where it is well-defined. /// /// A `Freeze` bound would also work, but `Send` *or* `Freeze` cannot be expressed. impl DeepClone for Gc { #[inline] fn deep_clone(&self) -> Gc { Gc::new(self.borrow().deep_clone()) } } #[cfg(test)] mod tests { use prelude::*; use super::*; use cell::RefCell; #[test] fn test_clone() { let x = Gc::new(RefCell::new(5)); let y = x.clone(); x.borrow().with_mut(|inner| { *inner = 20; }); assert_eq!(y.borrow().with(|x| *x), 20); } #[test] fn test_deep_clone() { let x = Gc::new(RefCell::new(5)); let y = x.deep_clone(); x.borrow().with_mut(|inner| { *inner = 20; }); assert_eq!(y.borrow().with(|x| *x), 5); } #[test] fn test_simple() { let x = Gc::new(5); assert_eq!(*x.borrow(), 5); } #[test] fn test_simple_clone() { let x = Gc::new(5); let y = x.clone(); assert_eq!(*x.borrow(), 5); assert_eq!(*y.borrow(), 5); } #[test] fn test_ptr_eq() { let x = Gc::new(5); let y = x.clone(); let z = Gc::new(7); assert!(x.ptr_eq(&x)); assert!(x.ptr_eq(&y)); assert!(!x.ptr_eq(&z)); } #[test] fn test_destructor() { let x = Gc::new(~5); assert_eq!(**x.borrow(), 5); } }