use super::edit::*;
use std::ops::{Deref, DerefMut};
pub trait Editable<T: ?Sized> {
fn edit(&self) -> Option<Editor<T>>;
fn read(&self) -> Option<Reader<T>>;
}
pub struct Reader<'a, T: ?Sized+'a> {
target: Box<'a+Deref<Target=T>>
}
pub struct Editor<'a, T: ?Sized+'a> {
target: Box<'a+DerefMut<Target=T>>,
}
impl<'a, T: ?Sized+'a> Reader<'a, T> {
pub fn new<Owner: 'a+Deref<Target=T>>(target: Owner) -> Reader<'a, T> {
Reader { target: Box::new(target) }
}
}
impl<'a, T: ?Sized+'a> Editor<'a, T> {
pub fn new<Owner: 'a+DerefMut<Target=T>>(target: Owner) -> Editor<'a, T> {
Editor { target: Box::new(target) }
}
}
impl<'a, T: ?Sized+'a> Deref for Reader<'a, T> {
type Target = T;
fn deref(&self) -> &T {
self.target.deref()
}
}
impl<'a, T: ?Sized+'a> Deref for Editor<'a, T> {
type Target = T;
fn deref(&self) -> &T {
self.target.deref()
}
}
impl<'a, T: ?Sized+'a> DerefMut for Editor<'a, T> {
fn deref_mut(&mut self) -> &mut T {
self.target.deref_mut()
}
}
impl<T: ?Sized> Editable<T> for () {
fn edit(&self) -> Option<Editor<T>> { None }
fn read(&self) -> Option<Reader<T>> { None }
}
pub fn open_read<'a, EditorType: ?Sized>(editable: &'a Editable<EditorType>) -> Option<Reader<'a, EditorType>> {
editable.read()
}
pub fn open_edit<'a, EditorType: ?Sized>(editable: &'a Editable<EditorType>) -> Option<Editor<'a, EditorType>> {
editable.edit()
}
pub trait PerformEdits<Edit> {
fn perform_edits<Iter: IntoIterator<Item=Edit>>(&self, edits: Iter);
fn set_pending(&self, pending: &[Edit]);
fn commit_pending(&self);
}
impl<Edit, T: Editable<PendingEditLog<Edit>>> PerformEdits<Edit> for T {
#[inline]
fn perform_edits<Iter: IntoIterator<Item=Edit>>(&self, edits: Iter) {
let mut editor = open_edit::<PendingEditLog<Edit>>(self).unwrap();
let edits: Vec<_> = edits.into_iter().collect();
editor.set_pending(&edits);
editor.commit_pending();
}
#[inline]
fn set_pending(&self, edits: &[Edit]) {
let mut editor = open_edit::<PendingEditLog<Edit>>(self).unwrap();
editor.set_pending(edits);
}
#[inline]
fn commit_pending(&self) {
let mut editor = open_edit::<PendingEditLog<Edit>>(self).unwrap();
editor.commit_pending();
}
}
#[cfg(test)]
mod test {
use super::*;
use std::sync::*;
#[test]
fn can_create_reader_for_mutex() {
let mutex = Mutex::new(1);
{
let reader = {
let locked = mutex.lock().unwrap();
Reader::new(locked)
};
assert!(*reader == 1);
}
}
#[test]
fn can_create_editor_for_mutex() {
let mutex = Mutex::new(1);
{
let mut editor = {
let locked = mutex.lock().unwrap();
Editor::new(locked)
};
assert!(*editor == 1);
*editor = 2;
}
assert!(*mutex.lock().unwrap() == 2);
}
struct TestEditable;
impl Editable<i32> for TestEditable {
fn edit(&self) -> Option<Editor<i32>> { None }
fn read(&self) -> Option<Reader<i32>> { None }
}
impl Editable<bool> for TestEditable {
fn edit(&self) -> Option<Editor<bool>> { None }
fn read(&self) -> Option<Reader<bool>> { None }
}
#[test]
fn can_have_multiple_editable_items() {
let test = TestEditable;
let edit_i32:Option<Editor<i32>> = test.edit();
let edit_bool = open_edit::<bool>(&test);
assert!(edit_i32.is_none());
assert!(edit_bool.is_none());
}
}