diff --git a/book/04-tags.md b/book/04-tags.md index 0df7386..327860f 100644 --- a/book/04-tags.md +++ b/book/04-tags.md @@ -218,6 +218,38 @@ impl Tags { pub fn has(&self, name: &str) -> bool { self.find(name).is_some() } + + /// Append a tag built from a name and a list of values. Returns + /// `self` so the call can chain. + pub fn add(mut self, name: N, values: V) -> Self + where + N: Into, + V: IntoIterator, + S: Into, + { + self.0.push(Tag::new(name, values)); + self + } + + /// Remove every tag with the given name. Returns `self` so the + /// call can chain. + pub fn remove(mut self, name: &str) -> Self { + self.0.retain(|t| t.name() != name); + self + } + + /// Replace every tag with the given name by a single new tag + /// built from `name` and `values`. Equivalent to `remove(name)` + /// followed by `add(Tag::new(name, values))`. + pub fn set(self, name: N, values: V) -> Self + where + N: Into, + V: IntoIterator, + S: Into, + { + let name = name.into(); + self.remove(&name).add(name, values) + } } impl std::ops::Deref for Tags { @@ -251,6 +283,21 @@ variants. Checking whether a collection mentions a particular pubkey is `tags.values("p").any(|p| p == hex)` — the code reads the way the question sounds. +Mutation is just as flat. `add` appends a tag; `remove` drops every +tag with a given name; `set` replaces every tag of a given name with +a single fresh one, which is the common case when a replaceable kind +is rewriting one of its own singleton fields. All three consume and +return `self`, so assembling or rewriting a collection reads as one +expression: + +```rust +let tags = Tags::new() + .add("t", ["nostr"]) // [["t", "nostr"]] + .add("t", ["rust"]) // [["t", "nostr"], ["t", "rust"]] + .set("t", ["nothing"]) // [["t", "nothing"]] + .remove("t"); // [] +``` + ## What's next Tags are the structured-data building block that every other type in diff --git a/book/05-events.md b/book/05-events.md index 03812ab..d01eb2a 100644 --- a/book/05-events.md +++ b/book/05-events.md @@ -100,17 +100,38 @@ other events, pubkeys, topics, and whatever else. Tags and content travel together because tags are part of what the hash commits to — they are not metadata in the "could be added later" sense. +`EventContent` is a builder. `new` hands back an empty payload and +chainable `content` and `tags` setters fill it in. Neither field is +required at construction time — a zero-length note with no tags is a +perfectly legal kind-1 event — and the builder shape means callers +don't have to pass `""` or `vec![]` placeholders when they only care +about one of the two. + ```rust {file=coracle-lib/src/events.rs} /// The content of an event: the human-readable body plus its tags. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct EventContent { pub content: String, pub tags: Tags, } impl EventContent { - pub fn new(content: impl Into, tags: impl Into) -> Self { - EventContent { content: content.into(), tags: tags.into() } + /// An empty payload: no content, no tags. + pub fn new() -> Self { + Self::default() + } + + /// Set the human-readable content. Returns `self` so the call can + /// chain. + pub fn content(mut self, content: impl Into) -> Self { + self.content = content.into(); + self + } + + /// Set the tags. Returns `self` so the call can chain. + pub fn tags(mut self, tags: impl Into) -> Self { + self.tags = tags.into(); + self } } ``` @@ -324,7 +345,8 @@ With that in place, the full pipeline from "hello nostr" to a signed event is one expression: ```rust -let hashed = EventContent::new("hello nostr", vec![]) +let hashed = EventContent::new() + .content("hello nostr") .kind(1) .stamp(1_700_000_000) .own(secret.public_key()) diff --git a/book/06-kinds.md b/book/06-kinds.md index 37cf05a..2130a5b 100644 --- a/book/06-kinds.md +++ b/book/06-kinds.md @@ -234,7 +234,9 @@ impl Kind for Deletion { } fn to_content(&self) -> EventContent { - EventContent::new(self.reason.clone(), self.tags.clone()) + EventContent::new() + .content(self.reason.clone()) + .tags(self.tags.clone()) } } ``` diff --git a/coracle-wasm/src/lib.rs b/coracle-wasm/src/lib.rs index f36cd3b..2710307 100644 --- a/coracle-wasm/src/lib.rs +++ b/coracle-wasm/src/lib.rs @@ -192,7 +192,9 @@ impl Event { .collect::>(), ); - let hashed = cev::EventContent::new(content, tags) + let hashed = cev::EventContent::new() + .content(content) + .tags(tags) .kind(kind) .stamp(created_at) .own(sk.0.public_key())