use std::borrow::Borrow;
use std::cell::RefCell;
use std::fmt::Debug;
use std::fmt::Formatter;
use std::fmt::{self};
use std::hash::Hash;
use std::hash::Hasher;
use std::marker::PhantomData;
use std::ops::Deref;
use std::rc::Rc;
use merc_collections::SetIndex;
use merc_unsafety::ProtectionIndex;
use merc_unsafety::ProtectionSet;
pub type LddIndex = SetIndex;
pub type SharedProtectionSet = Rc<RefCell<ProtectionSet<LddIndex>>>;
pub struct Ldd {
ldd: LddRef<'static>, root: ProtectionIndex, protection_set: SharedProtectionSet,
}
impl Ldd {
pub fn new(protection_set: &SharedProtectionSet, index: LddIndex) -> Ldd {
let root = protection_set.borrow_mut().protect(index);
Ldd {
protection_set: Rc::clone(protection_set),
ldd: LddRef::new(index),
root,
}
}
pub fn index(&self) -> LddIndex {
self.ldd.index
}
}
impl Deref for Ldd {
type Target = LddRef<'static>;
fn deref(&self) -> &Self::Target {
&self.ldd
}
}
impl<'a> Borrow<LddRef<'a>> for Ldd {
fn borrow(&self) -> &LddRef<'a> {
&self.ldd
}
}
impl Clone for Ldd {
fn clone(&self) -> Self {
Ldd::new(&self.protection_set, self.index())
}
}
impl Drop for Ldd {
fn drop(&mut self) {
self.protection_set.borrow_mut().unprotect(self.root);
}
}
impl PartialEq for Ldd {
fn eq(&self, other: &Self) -> bool {
debug_assert!(
Rc::ptr_eq(&self.protection_set, &other.protection_set),
"Both LDDs should refer to the same storage."
);
self.index() == other.index()
}
}
impl Debug for Ldd {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "index: {}", self.index())
}
}
impl Hash for Ldd {
fn hash<H: Hasher>(&self, state: &mut H) {
self.index().hash(state);
}
}
impl Eq for Ldd {}
#[derive(Hash, PartialEq, Eq)]
pub struct LddRef<'a> {
index: LddIndex, marker: PhantomData<&'a ()>,
}
impl<'a> LddRef<'a> {
pub fn new(index: LddIndex) -> LddRef<'a> {
LddRef {
index,
marker: PhantomData,
}
}
pub fn index(&self) -> LddIndex {
self.index
}
pub fn borrow(&self) -> LddRef<'_> {
LddRef::new(self.index())
}
}
impl fmt::Debug for LddRef<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "index: {}", self.index())
}
}
impl PartialEq<Ldd> for LddRef<'_> {
fn eq(&self, other: &Ldd) -> bool {
self.index == other.index()
}
}