Skip to content

Instantly share code, notes, and snippets.

@epilys

epilys/demo.mp4 Secret

Last active April 1, 2022 13:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save epilys/99fb75129c58b003b0b10c778f442b86 to your computer and use it in GitHub Desktop.
Save epilys/99fb75129c58b003b0b10c778f442b86 to your computer and use it in GitHub Desktop.
mod imp {
use super::*;
#[derive(Debug)]
pub struct Event {
pub timestamp: u64,
pub action: super::Action,
}
#[derive(Debug, Default)]
pub struct UndoDatabase {
pub database: RefCell<Vec<Event>>,
pub timestamp: RefCell<u64>,
pub cursor: RefCell<usize>,
}
#[glib::object_subclass]
impl ObjectSubclass for UndoDatabase {
const NAME: &'static str = "UndoDatabase";
type Type = super::UndoDatabase;
type ParentType = glib::Object;
type Interfaces = ();
}
impl ObjectImpl for UndoDatabase {}
}
impl Default for UndoDatabase {
fn default() -> Self {
Self::new()
}
}
pub struct EventStamp {
pub t: std::any::TypeId,
//FIXME: add also a weak object ref here
pub property: &'static str,
pub id: Box<[u8]>,
}
impl PartialEq for EventStamp {
fn eq(&self, other: &Self) -> bool {
self.t == other.t && self.property == other.property && self.id == other.id
}
}
impl Eq for EventStamp {}
impl UndoDatabase {
pub fn new() -> Self {
let ret: Self = glib::Object::new::<Self>(&[]).unwrap();
ret
}
pub fn event(&self, action: Action) {
let mut cursor = self.imp().cursor.borrow_mut();
let mut db = self.imp().database.borrow_mut();
let mut timestamp = self.imp().timestamp.borrow_mut();
*timestamp += 1;
let timestamp = *timestamp - 1;
db.drain(*cursor..);
db.push(Event { timestamp, action });
*cursor = db.len();
}
pub fn undo(&self) {
let mut cursor = self.imp().cursor.borrow_mut();
let mut db = self.imp().database.borrow_mut();
loop {
if let Some(last) = db[..*cursor].last_mut() {
std::dbg!(&last);
(last.action.undo)();
} else {
break;
}
if *cursor == 0 {
break;
}
*cursor -= 1;
match std::dbg!((db[..*cursor].last(), db[..*cursor + 1].last())) {
(Some(prev), Some(cur))
if std::dbg!(
prev.action.stamp == cur.action.stamp
&& prev.action.compress
&& cur.action.compress
) => {}
_ => break,
}
}
}
pub fn redo(&self) {
let mut cursor = self.imp().cursor.borrow_mut();
let mut db = self.imp().database.borrow_mut();
loop {
if let Some(last) = db.get_mut(*cursor) {
std::dbg!(&last);
(last.action.redo)();
} else {
break;
}
*cursor += 1;
if *cursor >= db.len() {
*cursor = std::cmp::min(db.len(), *cursor);
break;
}
match std::dbg!((db.get(*cursor - 1), db.get(*cursor))) {
(Some(prev), Some(cur))
if std::dbg!(
prev.action.stamp == cur.action.stamp
&& prev.action.compress
&& cur.action.compress
) => {}
_ => break,
}
}
}
}
pub struct Action {
pub stamp: EventStamp,
pub compress: bool,
pub redo: Box<dyn FnMut()>,
pub undo: Box<dyn FnMut()>,
}
impl std::fmt::Debug for Action {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
fmt.debug_struct("Action")
.field("compress", &self.compress)
.field(
"stamp",
&format!(
"{:?} {} {:?}",
self.stamp.t, self.stamp.property, self.stamp.id
),
)
.finish()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment