Use traits to keep event methods dry

This commit is contained in:
Jon Staab
2026-05-20 14:27:26 -07:00
parent 8ad0bc393b
commit d0709e1811
7 changed files with 138 additions and 61 deletions
+24 -32
View File
@@ -33,13 +33,13 @@ pub mod expiration;
//! NIP-40 expiring events: reading the `expiration` tag and checking
//! whether an event has expired.
//!
//! The free functions in this module operate on [`Tags`] so they can
//! be used wherever a tag slice is in hand. Method versions on
//! [`HashedEvent`] and [`Event`] delegate to them for a readable call
//! site. The tag itself is built with [`Tag::expiration`] from the
//! tags module.
//! The free functions in this module operate on [`Tags`] so they can be
//! used wherever a tag slice is in hand. The [`EventExtensionExpiration`]
//! trait layers method-call sugar on top for any event type, reachable
//! through the crate prelude. The tag itself is built with
//! [`Tag::expiration`] from the tags module.
use crate::events::{Event, HashedEvent};
use crate::events::HasTags;
use crate::tags::Tags;
use crate::util::now;
```
@@ -128,45 +128,37 @@ impl Tag {
## Methods on event types
Both `HashedEvent` and `Event` carry a `Tags` field, and callers who
have an event in hand almost always want to ask questions of its tags
without a separate import. The method impls delegate to the free
functions verbatim.
Rather than repeat these queries on each event struct, expiration exposes
them through an extension trait bounded on [`HasTags`]. The method bodies
live once, as defaults, and a blanket impl makes them available on every
type that can hand back its tags — `HashedEvent`, `Event`, and anything
added later. With `coracle_lib::prelude::*` in scope, `event.is_expired()`
reads the same whether the event is hashed or signed.
```rust {file=coracle-lib/src/expiration.rs}
impl HashedEvent {
/// Expiration queries on any event that carries tags.
pub trait EventExtensionExpiration: HasTags {
/// Return the expiration timestamp of this event, if any.
pub fn get_expiration(&self) -> Option<u64> {
get_expiration(&self.tags)
fn get_expiration(&self) -> Option<u64> {
get_expiration(self.tags())
}
/// Whether this event has expired relative to the given timestamp.
pub fn is_expired_at(&self, now: u64) -> bool {
is_expired_at(&self.tags, now)
fn is_expired_at(&self, now: u64) -> bool {
is_expired_at(self.tags(), now)
}
/// Whether this event has expired relative to the system clock.
pub fn is_expired(&self) -> bool {
is_expired(&self.tags)
fn is_expired(&self) -> bool {
is_expired(self.tags())
}
}
impl Event {
/// Return the expiration timestamp of this event, if any.
pub fn get_expiration(&self) -> Option<u64> {
get_expiration(&self.tags)
}
impl<T: HasTags> EventExtensionExpiration for T {}
```
/// Whether this event has expired relative to the given timestamp.
pub fn is_expired_at(&self, now: u64) -> bool {
is_expired_at(&self.tags, now)
}
/// Whether this event has expired relative to the system clock.
pub fn is_expired(&self) -> bool {
is_expired(&self.tags)
}
}
```rust {file=coracle-lib/src/prelude.rs}
pub use crate::expiration::EventExtensionExpiration;
```
## Usage patterns