use std::borrow::Cow;
use std::fmt;
use flatbuffers::InvalidFlatbuffer;
pub use flatbuffers::{FlatBufferBuilder, ForwardsUOffset, Vector};
use nostr::prelude::*;
use nostr::secp256k1;
use nostr::secp256k1::schnorr::Signature;
#[allow(
unused_imports,
dead_code,
clippy::all,
unsafe_code,
missing_docs,
unsafe_op_in_unsafe_fn
)]
mod event_generated;
pub use self::event_generated::event_fbs;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MissingField {
Id,
Pubkey,
Tags,
Content,
Sig,
}
impl fmt::Display for MissingField {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Id => write!(f, "id"),
Self::Pubkey => write!(f, "pubkey"),
Self::Tags => write!(f, "tags"),
Self::Content => write!(f, "content"),
Self::Sig => write!(f, "sig"),
}
}
}
#[derive(Debug)]
pub enum Error {
Protocol(nostr::error::Error),
FlatBuffer(InvalidFlatbuffer),
Secp256k1(secp256k1::Error),
FieldNotFound(MissingField),
}
impl std::error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Protocol(e) => e.fmt(f),
Self::FlatBuffer(e) => write!(f, "{e}"),
Self::Secp256k1(e) => write!(f, "{e}"),
Self::FieldNotFound(field) => write!(f, "'{field}' field not found"),
}
}
}
impl From<nostr::error::Error> for Error {
fn from(e: nostr::error::Error) -> Self {
Self::Protocol(e)
}
}
impl From<InvalidFlatbuffer> for Error {
fn from(e: InvalidFlatbuffer) -> Self {
Self::FlatBuffer(e)
}
}
impl From<secp256k1::Error> for Error {
fn from(e: secp256k1::Error) -> Self {
Self::Secp256k1(e)
}
}
pub trait FlatBufferEncode {
fn encode<'a>(&self, fbb: &'a mut FlatBufferBuilder) -> &'a [u8];
}
pub trait FlatBufferDecode: Sized {
fn decode(buf: &[u8]) -> Result<Self, Error>;
}
pub trait FlatBufferDecodeBorrowed<'a>: Sized {
fn decode(buf: &'a [u8]) -> Result<Self, Error>;
}
impl FlatBufferEncode for Event {
fn encode<'a>(&self, fbb: &'a mut FlatBufferBuilder) -> &'a [u8] {
fbb.reset();
let id = event_fbs::Fixed32Bytes::new(self.id.as_bytes());
let pubkey = event_fbs::Fixed32Bytes::new(self.pubkey.as_bytes());
let sig = event_fbs::Fixed64Bytes::new(self.sig.as_ref());
let tags = self
.tags
.iter()
.map(|t| {
let tags = t
.as_slice()
.iter()
.map(|t| fbb.create_string(t))
.collect::<Vec<_>>();
let args = event_fbs::StringVectorArgs {
data: Some(fbb.create_vector(&tags)),
};
event_fbs::StringVector::create(fbb, &args)
})
.collect::<Vec<_>>();
let args = event_fbs::EventArgs {
id: Some(&id),
pubkey: Some(&pubkey),
created_at: self.created_at.as_secs(),
kind: self.kind.as_u16() as u64,
tags: Some(fbb.create_vector(&tags)),
content: Some(fbb.create_string(&self.content)),
sig: Some(&sig),
};
let offset = event_fbs::Event::create(fbb, &args);
event_fbs::finish_event_buffer(fbb, offset);
fbb.finished_data()
}
}
impl FlatBufferDecode for Event {
fn decode(buf: &[u8]) -> Result<Self, Error> {
let ev = event_fbs::root_as_event(buf)?;
let tags = ev
.tags()
.ok_or(Error::FieldNotFound(MissingField::Tags))?
.into_iter()
.filter_map(|tag| tag.data().map(Tag::parse))
.collect::<Result<Vec<Tag>, _>>()?;
Ok(Self::new(
EventId::from_byte_array(ev.id().ok_or(Error::FieldNotFound(MissingField::Id))?.0),
PublicKey::from_byte_array(
ev.pubkey()
.ok_or(Error::FieldNotFound(MissingField::Pubkey))?
.0,
),
Timestamp::from(ev.created_at()),
Kind::from(ev.kind() as u16),
tags,
ev.content()
.ok_or(Error::FieldNotFound(MissingField::Content))?
.to_owned(),
Signature::from_slice(&ev.sig().ok_or(Error::FieldNotFound(MissingField::Sig))?.0)?,
))
}
}
impl<'a> FlatBufferDecodeBorrowed<'a> for EventBorrow<'a> {
fn decode(buf: &'a [u8]) -> Result<Self, Error> {
let ev = event_fbs::root_as_event(buf)?;
let fb_tags = ev.tags().ok_or(Error::FieldNotFound(MissingField::Tags))?;
let mut tags = Vec::with_capacity(fb_tags.len());
for tag in fb_tags.iter().filter_map(|t| t.data()) {
tags.push(CowTag::parse(tag.into_iter().map(Cow::Borrowed).collect())?);
}
Ok(Self {
id: &ev.id().ok_or(Error::FieldNotFound(MissingField::Id))?.0,
pubkey: &ev
.pubkey()
.ok_or(Error::FieldNotFound(MissingField::Pubkey))?
.0,
created_at: Timestamp::from_secs(ev.created_at()),
kind: ev.kind() as u16, tags,
content: ev
.content()
.ok_or(Error::FieldNotFound(MissingField::Content))?,
sig: &ev.sig().ok_or(Error::FieldNotFound(MissingField::Sig))?.0,
})
}
}
#[cfg(bench)]
mod benches {
use super::*;
use crate::test::{Bencher, black_box};
#[bench]
pub fn bench_decode_flatbuf_event_borrow(bh: &mut Bencher) {
let json = r#"{
"content": "+",
"created_at": 1716508454,
"id": "3e9e9c2fbf263590860a9c60a7de6b0d166230a5a15aa8dcdb70f537cec9807a",
"kind": 7,
"pubkey": "3bbddb5c7233ad993b41cb639e63122120f391b8580a9b83aae33c648230e0a3",
"sig": "3f2ba6d713e4851500b81de2d2ef44b72f1eff061898bf8488e74f7e4ed141b0dadab4c3a9c6b237f3a6db83171bd41eafd7ab973f6fb067a4305e95abeadeee",
"tags": [
[
"e",
"e1e786c60ed884b6e784712aaf70e63b848b7403ef651b52b701d87739ea1808",
"",
"",
"04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9"
],
[
"p",
"04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9"
]
]
}"#;
let event = Event::from_json(json).unwrap();
let mut fbb = FlatBufferBuilder::new();
let bytes = event.encode(&mut fbb);
bh.iter(|| {
black_box(EventBorrow::decode(bytes)).unwrap();
});
}
}