Add some utility methods to tags
This commit is contained in:
@@ -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<N, V, S>(mut self, name: N, values: V) -> Self
|
||||
where
|
||||
N: Into<String>,
|
||||
V: IntoIterator<Item = S>,
|
||||
S: Into<String>,
|
||||
{
|
||||
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<N, V, S>(self, name: N, values: V) -> Self
|
||||
where
|
||||
N: Into<String>,
|
||||
V: IntoIterator<Item = S>,
|
||||
S: Into<String>,
|
||||
{
|
||||
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
|
||||
|
||||
+26
-4
@@ -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<String>, tags: impl Into<Tags>) -> 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<String>) -> Self {
|
||||
self.content = content.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the tags. Returns `self` so the call can chain.
|
||||
pub fn tags(mut self, tags: impl Into<Tags>) -> 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())
|
||||
|
||||
+3
-1
@@ -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())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user