Skip to content

Commit

Permalink
event docs
Browse files Browse the repository at this point in the history
  • Loading branch information
JieningYu committed Aug 13, 2023
1 parent 78cd524 commit 4c9b18d
Showing 1 changed file with 69 additions and 5 deletions.
74 changes: 69 additions & 5 deletions src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,23 +282,42 @@ impl<T> Freeze<T> for T {
}
}

/// A type containing listeners of this event,
/// which can be invoked by an invoker.
///
/// The listeners are sorted by phases ([`i8`] by default)
/// that can be called by order.
///
/// This type was inspired by the event system in Fabric API.
pub struct Event<T, Phase = i8>
where
T: ?Sized + 'static,
Phase: Ord,
{
listeners_and_cache:
parking_lot::RwLock<(Vec<(Phase, *const T)>, Option<Box<T>>, Vec<&'static T>)>,
/// Whether listeners has been modified before requesting the invoker.
dirty: std::sync::atomic::AtomicBool,

invoker_factory: fn(&'static [&'static T]) -> Box<T>,

dirty: std::sync::atomic::AtomicBool,
/// 0: raw listeners with phases
/// 1: cached invoker
/// 2: cached listener references
listeners_and_cache:
parking_lot::RwLock<(Vec<(Phase, *const T)>, Option<Box<T>>, Vec<&'static T>)>,
}

impl<T, Phase> Event<T, Phase>
where
T: ?Sized,
Phase: Ord,
{
/// Create a new event with provided event factory.
///
/// To avoid lifetime problems in the factory, listeners
/// provied are all in static references so that they're
/// able to be copied and moved.
/// So you should add a `move` keyword before the closure
/// to return in the factory.
pub const fn new(invoker_factory: fn(&'static [&'static T]) -> Box<T>) -> Self {
Self {
listeners_and_cache: parking_lot::RwLock::new((Vec::new(), None, Vec::new())),
Expand All @@ -307,6 +326,11 @@ where
}
}

/// Get the invoker of this event.
///
/// Once the invoker is created, it will be cached until
/// the next modification of listeners, and will be re-created
/// by the factory.
pub fn invoker(&self) -> &T {
if self.dirty.load(std::sync::atomic::Ordering::Acquire) {
let mut write_guard = self.listeners_and_cache.write();
Expand All @@ -328,6 +352,7 @@ where
unsafe { &*(self.listeners_and_cache.read().1.as_ref().unwrap().deref() as *const T) }
}

/// Register a listener to this event for the specified phase.
pub fn register_with_phase(&mut self, listener: Box<T>, phase: Phase) {
self.listeners_and_cache
.get_mut()
Expand All @@ -345,6 +370,7 @@ where
T: ?Sized,
Phase: Ord + Default,
{
/// Register a listener to this event for the default phase.
pub fn register(&mut self, listener: Box<T>) {
self.register_with_phase(listener, Default::default())
}
Expand Down Expand Up @@ -392,15 +418,17 @@ mod event_tests {
return false;
}
}

true
})
});

assert!(event.invoker()(
"minecraft by mojang is a propritary software."
));

event.register(Box::new(|string| {
!string.to_lowercase().contains("propritary software")
}));

event.register(Box::new(|string| !string.to_lowercase().contains("mojang")));
event.register(Box::new(|string| {
!string.to_lowercase().contains("minecraft")
Expand All @@ -416,4 +444,40 @@ mod event_tests {

assert!(!event.invoker()("i love krlite."));
}

#[test]
fn phases() {
let mut event: Event<dyn Fn(&mut String)> = Event::new(|listeners| {
Box::new(move |string| {
for listener in listeners {
listener(string);
}
})
});

event.register(Box::new(|string| string.push_str("genshin impact ")));
event.register_with_phase(Box::new(|string| string.push_str("you're right, ")), -3);
event.register_with_phase(Box::new(|string| string.push_str("but ")), -2);
event.register_with_phase(Box::new(|string| string.push_str("is a...")), 10);

{
let mut string = String::new();
event.invoker()(&mut string);
assert_eq!(string, "you're right, but genshin impact is a...");
}

event.register_with_phase(
Box::new(|string| string.push_str("genshin impact, bootstrap! ")),
-100,
);

{
let mut string = String::new();
event.invoker()(&mut string);
assert_eq!(
string,
"genshin impact, bootstrap! you're right, but genshin impact is a..."
);
}
}
}

0 comments on commit 4c9b18d

Please sign in to comment.