Use traits to keep event methods dry
This commit is contained in:
@@ -525,6 +525,86 @@ Deserialization does not verify the signature. Parsing is cheap; `verify()`
|
||||
is not, and there are many places where you want to read an event off disk
|
||||
without paying for a signature check.
|
||||
|
||||
## A shared surface across event stages
|
||||
|
||||
There is a lot of overlap between various event structs. A few minimal accessor
|
||||
traits capture read access to various fields so that we can define extensions
|
||||
to events without duplication.
|
||||
|
||||
```rust {file=coracle-lib/src/events.rs}
|
||||
pub trait HasTags {
|
||||
fn tags(&self) -> &Tags;
|
||||
}
|
||||
|
||||
pub trait HasId {
|
||||
fn id(&self) -> &[u8; 32];
|
||||
}
|
||||
|
||||
impl HasTags for HashedEvent {
|
||||
fn tags(&self) -> &Tags {
|
||||
&self.tags
|
||||
}
|
||||
}
|
||||
|
||||
impl HasTags for Event {
|
||||
fn tags(&self) -> &Tags {
|
||||
&self.tags
|
||||
}
|
||||
}
|
||||
|
||||
impl HasId for HashedEvent {
|
||||
fn id(&self) -> &[u8; 32] {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl HasId for Event {
|
||||
fn id(&self) -> &[u8; 32] {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Subsequent chapters will add *extension traits* bounded on these accessors,
|
||||
supply the method bodies as defaults, and close with a blanket impl over every
|
||||
type that satisfies the bound. The logic is written once and reaches both event
|
||||
types — and any event type added later — without another line per struct.
|
||||
The expiration chapter's version reads like this:
|
||||
|
||||
```rust
|
||||
pub trait EventExtensionExpiration: HasTags {
|
||||
fn is_expired(&self) -> bool {
|
||||
is_expired(self.tags())
|
||||
}
|
||||
// ...the rest of the expiration queries
|
||||
}
|
||||
|
||||
impl<T: HasTags> EventExtensionExpiration for T {}
|
||||
```
|
||||
|
||||
A trait's methods are only callable where the trait is in scope, so the
|
||||
library gathers these extension traits in a `prelude`. One glob import brings
|
||||
the whole behavior-query surface along:
|
||||
|
||||
```rust
|
||||
use coracle_lib::prelude::*;
|
||||
```
|
||||
|
||||
```rust {file=coracle-lib/src/lib.rs}
|
||||
pub mod prelude;
|
||||
```
|
||||
|
||||
```rust {file=coracle-lib/src/prelude.rs}
|
||||
//! One-stop import for the extension traits that add behavior-tag queries to
|
||||
//! events. With `coracle_lib::prelude::*` in scope, methods like
|
||||
//! `is_expired`, `is_protected`, and `get_pow` become callable on
|
||||
//! `HashedEvent` and `Event`.
|
||||
|
||||
pub use crate::events::{HasId, HasTags};
|
||||
```
|
||||
|
||||
Each later chapter that defines an extension trait adds it to this prelude.
|
||||
|
||||
## What's next
|
||||
|
||||
The next chapter introduces kinds — the integer that decides how content
|
||||
|
||||
Reference in New Issue
Block a user