<commit_before>use std::cell::UnsafeCell;

use {Id, ShareId, ToMessage};
use runtime::{Message, Object};

#[allow(improper_ctypes)]
#[link(name = "Foundation", kind = "framework")]
extern {
	fn objc_storeWeak(location: *mut *mut Object, obj: *mut Object) -> *mut Object;
	fn objc_loadWeakRetained(location: *mut *mut Object) -> *mut Object;
	fn objc_destroyWeak(addr: *mut *mut Object);
}

pub struct WeakId<T> {
	// Our pointer must have the same address even if we are moved, so Box it.
	// Although loading the WeakId may modify the pointer, it is thread safe,
	// so we must use an UnsafeCell to get a *mut without self being mutable.
	ptr: Box<UnsafeCell<*const T>>,
}

impl<T: Message> WeakId<T> {
	pub fn new(obj: &ShareId<T>) -> WeakId<T> {
		let ptr = box UnsafeCell::new(RawPtr::null());
		unsafe {
			let loc = ptr.get() as *mut *mut Object;
			objc_storeWeak(loc, obj.as_ptr());
		}
		WeakId { ptr: ptr }
	}

	pub fn load(&self) -> Option<ShareId<T>> {
		unsafe {
			let loc = self.ptr.get() as *mut *mut Object;
			let obj = objc_loadWeakRetained(loc);
			Id::maybe_from_retained_ptr(obj as *mut T)
		}
	}
}

#[unsafe_destructor]
impl<T> Drop for WeakId<T> {
	fn drop(&mut self) {
		unsafe {
			let loc = self.ptr.get() as *mut *mut Object;
			objc_destroyWeak(loc);
		}
	}
}

#[cfg(test)]
mod tests {
	use {Id};
	use foundation::{INSObject, NSObject};
	use super::WeakId;

	#[test]
	fn test_weak() {
		let obj: Id<NSObject> = INSObject::new();
		let obj = obj.share();

		let weak = WeakId::new(&obj);
		let strong = weak.load().unwrap();
		assert!(strong == obj);
		drop(strong);

		drop(obj);
		assert!(weak.load().is_none());
	}
}<commit_msg>Don't use foundation in weak tests.<commit_after>use std::cell::UnsafeCell;

use {Id, ShareId, ToMessage};
use runtime::{Message, Object};

#[allow(improper_ctypes)]
#[link(name = "Foundation", kind = "framework")]
extern {
	fn objc_storeWeak(location: *mut *mut Object, obj: *mut Object) -> *mut Object;
	fn objc_loadWeakRetained(location: *mut *mut Object) -> *mut Object;
	fn objc_destroyWeak(addr: *mut *mut Object);
}

pub struct WeakId<T> {
	// Our pointer must have the same address even if we are moved, so Box it.
	// Although loading the WeakId may modify the pointer, it is thread safe,
	// so we must use an UnsafeCell to get a *mut without self being mutable.
	ptr: Box<UnsafeCell<*const T>>,
}

impl<T: Message> WeakId<T> {
	pub fn new(obj: &ShareId<T>) -> WeakId<T> {
		let ptr = box UnsafeCell::new(RawPtr::null());
		unsafe {
			let loc = ptr.get() as *mut *mut Object;
			objc_storeWeak(loc, obj.as_ptr());
		}
		WeakId { ptr: ptr }
	}

	pub fn load(&self) -> Option<ShareId<T>> {
		unsafe {
			let loc = self.ptr.get() as *mut *mut Object;
			let obj = objc_loadWeakRetained(loc);
			Id::maybe_from_retained_ptr(obj as *mut T)
		}
	}
}

#[unsafe_destructor]
impl<T> Drop for WeakId<T> {
	fn drop(&mut self) {
		unsafe {
			let loc = self.ptr.get() as *mut *mut Object;
			objc_destroyWeak(loc);
		}
	}
}

#[cfg(test)]
mod tests {
	use {Id};
	use runtime::{Class, Object};
	use super::WeakId;

	#[test]
	fn test_weak() {
		let cls = Class::get("NSObject").unwrap();
		let obj = unsafe {
			let obj = msg_send![cls alloc];
			let obj = msg_send![obj init];
			Id::from_retained_ptr(obj)
		};
		let obj = obj.share();

		let weak = WeakId::new(&obj);
		let strong = weak.load().unwrap();
		assert!(&*strong as *const Object == &*obj as *const Object);
		drop(strong);

		drop(obj);
		assert!(weak.load().is_none());
	}
}
{'fraction_non_alphanumeric': 0.1625178826895565, 'fraction_numerical': 0.0, 'mean_word_length': 4.044733044733045, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '839228', 'n_tokens_mistral': 1404, 'n_tokens_neox': 1302, 'n_words': 374}