Add some utility methods to tags
This commit is contained in:
@@ -218,6 +218,38 @@ impl Tags {
|
|||||||
pub fn has(&self, name: &str) -> bool {
|
pub fn has(&self, name: &str) -> bool {
|
||||||
self.find(name).is_some()
|
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 {
|
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
|
is `tags.values("p").any(|p| p == hex)` — the code reads the way the
|
||||||
question sounds.
|
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
|
## What's next
|
||||||
|
|
||||||
Tags are the structured-data building block that every other type in
|
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
|
together because tags are part of what the hash commits to — they are not
|
||||||
metadata in the "could be added later" sense.
|
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}
|
```rust {file=coracle-lib/src/events.rs}
|
||||||
/// The content of an event: the human-readable body plus its tags.
|
/// 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 struct EventContent {
|
||||||
pub content: String,
|
pub content: String,
|
||||||
pub tags: Tags,
|
pub tags: Tags,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventContent {
|
impl EventContent {
|
||||||
pub fn new(content: impl Into<String>, tags: impl Into<Tags>) -> Self {
|
/// An empty payload: no content, no tags.
|
||||||
EventContent { content: content.into(), tags: tags.into() }
|
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:
|
one expression:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let hashed = EventContent::new("hello nostr", vec![])
|
let hashed = EventContent::new()
|
||||||
|
.content("hello nostr")
|
||||||
.kind(1)
|
.kind(1)
|
||||||
.stamp(1_700_000_000)
|
.stamp(1_700_000_000)
|
||||||
.own(secret.public_key())
|
.own(secret.public_key())
|
||||||
|
|||||||
+3
-1
@@ -234,7 +234,9 @@ impl Kind for Deletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn to_content(&self) -> EventContent {
|
fn to_content(&self) -> EventContent {
|
||||||
EventContent::new(self.reason.clone(), self.tags.clone())
|
EventContent::new()
|
||||||
|
.content(self.reason.clone())
|
||||||
|
.tags(self.tags.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -192,7 +192,9 @@ impl Event {
|
|||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let hashed = cev::EventContent::new(content, tags)
|
let hashed = cev::EventContent::new()
|
||||||
|
.content(content)
|
||||||
|
.tags(tags)
|
||||||
.kind(kind)
|
.kind(kind)
|
||||||
.stamp(created_at)
|
.stamp(created_at)
|
||||||
.own(sk.0.public_key())
|
.own(sk.0.public_key())
|
||||||
|
|||||||
Reference in New Issue
Block a user