From 7071c299a3216ecfcf508f081d3b84838418df0f Mon Sep 17 00:00:00 2001 From: Yuki Kishimoto Date: Tue, 24 Oct 2023 12:41:02 +0200 Subject: [PATCH] Init `nostr-sdk-fbs` crate --- Makefile | 3 + crates/nostr-sdk-fbs/Cargo.toml | 11 + crates/nostr-sdk-fbs/Makefile | 4 + crates/nostr-sdk-fbs/fbs/event.fbs | 21 + crates/nostr-sdk-fbs/src/event_generated.rs | 492 ++++++++++++++++++++ crates/nostr-sdk-fbs/src/lib.rs | 36 ++ 6 files changed, 567 insertions(+) create mode 100644 crates/nostr-sdk-fbs/Cargo.toml create mode 100644 crates/nostr-sdk-fbs/Makefile create mode 100644 crates/nostr-sdk-fbs/fbs/event.fbs create mode 100644 crates/nostr-sdk-fbs/src/event_generated.rs create mode 100644 crates/nostr-sdk-fbs/src/lib.rs diff --git a/Makefile b/Makefile index 663819216..92f36d873 100644 --- a/Makefile +++ b/Makefile @@ -9,5 +9,8 @@ clean: book: cd book && make build +flatbuffers: + cd crates/nostr-sdk-fbs && make + loc: @echo "--- Counting lines of .rs files (LOC):" && find crates/ bindings/ -type f -name "*.rs" -exec cat {} \; | wc -l \ No newline at end of file diff --git a/crates/nostr-sdk-fbs/Cargo.toml b/crates/nostr-sdk-fbs/Cargo.toml new file mode 100644 index 000000000..19fbfdaf3 --- /dev/null +++ b/crates/nostr-sdk-fbs/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "nostr-sdk-fbs" +version = "0.1.0" +edition = "2021" +homepage.workspace = true +repository.workspace = true +license.workspace = true + +[dependencies] +flatbuffers = "23.5" +nostr = { version = "0.24", path = "../nostr", default-features = false, features = ["std"] } diff --git a/crates/nostr-sdk-fbs/Makefile b/crates/nostr-sdk-fbs/Makefile new file mode 100644 index 000000000..5f4a44898 --- /dev/null +++ b/crates/nostr-sdk-fbs/Makefile @@ -0,0 +1,4 @@ +all: build + +build: + flatc --rust -o ./src/ ./fbs/event.fbs \ No newline at end of file diff --git a/crates/nostr-sdk-fbs/fbs/event.fbs b/crates/nostr-sdk-fbs/fbs/event.fbs new file mode 100644 index 000000000..a2c0230a7 --- /dev/null +++ b/crates/nostr-sdk-fbs/fbs/event.fbs @@ -0,0 +1,21 @@ +namespace EventFbs; + +struct Fixed32Bytes { + val: [ubyte:32]; +} + +struct Fixed64Bytes { + val: [ubyte:64]; +} + +table Event { + id: Fixed32Bytes; + pubkey: Fixed32Bytes; + created_at: ulong; + kind: ulong; + tags: [string]; + content: string; + sig: Fixed64Bytes; +} + +root_type Event; \ No newline at end of file diff --git a/crates/nostr-sdk-fbs/src/event_generated.rs b/crates/nostr-sdk-fbs/src/event_generated.rs new file mode 100644 index 000000000..5bcfa10cd --- /dev/null +++ b/crates/nostr-sdk-fbs/src/event_generated.rs @@ -0,0 +1,492 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +// @generated + +use core::cmp::Ordering; +use core::mem; + +extern crate flatbuffers; +use self::flatbuffers::{EndianScalar, Follow}; + +#[allow(unused_imports, dead_code)] +pub mod event_fbs { + + use core::cmp::Ordering; + use core::mem; + + extern crate flatbuffers; + use self::flatbuffers::{EndianScalar, Follow}; + + // struct Fixed32Bytes, aligned to 1 + #[repr(transparent)] + #[derive(Clone, Copy, PartialEq)] + pub struct Fixed32Bytes(pub [u8; 32]); + impl Default for Fixed32Bytes { + fn default() -> Self { + Self([0; 32]) + } + } + impl core::fmt::Debug for Fixed32Bytes { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + f.debug_struct("Fixed32Bytes") + .field("val", &self.val()) + .finish() + } + } + + impl flatbuffers::SimpleToVerifyInSlice for Fixed32Bytes {} + impl<'a> flatbuffers::Follow<'a> for Fixed32Bytes { + type Inner = &'a Fixed32Bytes; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + <&'a Fixed32Bytes>::follow(buf, loc) + } + } + impl<'a> flatbuffers::Follow<'a> for &'a Fixed32Bytes { + type Inner = &'a Fixed32Bytes; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + flatbuffers::follow_cast_ref::(buf, loc) + } + } + impl<'b> flatbuffers::Push for Fixed32Bytes { + type Output = Fixed32Bytes; + #[inline] + unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { + let src = ::core::slice::from_raw_parts( + self as *const Fixed32Bytes as *const u8, + Self::size(), + ); + dst.copy_from_slice(src); + } + } + + impl<'a> flatbuffers::Verifiable for Fixed32Bytes { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, + pos: usize, + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.in_buffer::(pos) + } + } + + impl<'a> Fixed32Bytes { + #[allow(clippy::too_many_arguments)] + pub fn new(val: &[u8; 32]) -> Self { + let mut s = Self([0; 32]); + s.set_val(val); + s + } + + pub fn val(&'a self) -> flatbuffers::Array<'a, u8, 32> { + // Safety: + // Created from a valid Table for this object + // Which contains a valid array in this slot + unsafe { flatbuffers::Array::follow(&self.0, 0) } + } + + pub fn set_val(&mut self, items: &[u8; 32]) { + // Safety: + // Created from a valid Table for this object + // Which contains a valid array in this slot + unsafe { flatbuffers::emplace_scalar_array(&mut self.0, 0, items) }; + } + } + + // struct Fixed64Bytes, aligned to 1 + #[repr(transparent)] + #[derive(Clone, Copy, PartialEq)] + pub struct Fixed64Bytes(pub [u8; 64]); + impl Default for Fixed64Bytes { + fn default() -> Self { + Self([0; 64]) + } + } + impl core::fmt::Debug for Fixed64Bytes { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + f.debug_struct("Fixed64Bytes") + .field("val", &self.val()) + .finish() + } + } + + impl flatbuffers::SimpleToVerifyInSlice for Fixed64Bytes {} + impl<'a> flatbuffers::Follow<'a> for Fixed64Bytes { + type Inner = &'a Fixed64Bytes; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + <&'a Fixed64Bytes>::follow(buf, loc) + } + } + impl<'a> flatbuffers::Follow<'a> for &'a Fixed64Bytes { + type Inner = &'a Fixed64Bytes; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + flatbuffers::follow_cast_ref::(buf, loc) + } + } + impl<'b> flatbuffers::Push for Fixed64Bytes { + type Output = Fixed64Bytes; + #[inline] + unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { + let src = ::core::slice::from_raw_parts( + self as *const Fixed64Bytes as *const u8, + Self::size(), + ); + dst.copy_from_slice(src); + } + } + + impl<'a> flatbuffers::Verifiable for Fixed64Bytes { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, + pos: usize, + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.in_buffer::(pos) + } + } + + impl<'a> Fixed64Bytes { + #[allow(clippy::too_many_arguments)] + pub fn new(val: &[u8; 64]) -> Self { + let mut s = Self([0; 64]); + s.set_val(val); + s + } + + pub fn val(&'a self) -> flatbuffers::Array<'a, u8, 64> { + // Safety: + // Created from a valid Table for this object + // Which contains a valid array in this slot + unsafe { flatbuffers::Array::follow(&self.0, 0) } + } + + pub fn set_val(&mut self, items: &[u8; 64]) { + // Safety: + // Created from a valid Table for this object + // Which contains a valid array in this slot + unsafe { flatbuffers::emplace_scalar_array(&mut self.0, 0, items) }; + } + } + + pub enum EventOffset {} + #[derive(Copy, Clone, PartialEq)] + + pub struct Event<'a> { + pub _tab: flatbuffers::Table<'a>, + } + + impl<'a> flatbuffers::Follow<'a> for Event<'a> { + type Inner = Event<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table::new(buf, loc), + } + } + } + + impl<'a> Event<'a> { + pub const VT_ID: flatbuffers::VOffsetT = 4; + pub const VT_PUBKEY: flatbuffers::VOffsetT = 6; + pub const VT_CREATED_AT: flatbuffers::VOffsetT = 8; + pub const VT_KIND: flatbuffers::VOffsetT = 10; + pub const VT_TAGS: flatbuffers::VOffsetT = 12; + pub const VT_CONTENT: flatbuffers::VOffsetT = 14; + pub const VT_SIG: flatbuffers::VOffsetT = 16; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + Event { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args EventArgs<'args>, + ) -> flatbuffers::WIPOffset> { + let mut builder = EventBuilder::new(_fbb); + builder.add_kind(args.kind); + builder.add_created_at(args.created_at); + if let Some(x) = args.sig { + builder.add_sig(x); + } + if let Some(x) = args.content { + builder.add_content(x); + } + if let Some(x) = args.tags { + builder.add_tags(x); + } + if let Some(x) = args.pubkey { + builder.add_pubkey(x); + } + if let Some(x) = args.id { + builder.add_id(x); + } + builder.finish() + } + + #[inline] + pub fn id(&self) -> Option<&'a Fixed32Bytes> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Event::VT_ID, None) } + } + #[inline] + pub fn pubkey(&self) -> Option<&'a Fixed32Bytes> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Event::VT_PUBKEY, None) } + } + #[inline] + pub fn created_at(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Event::VT_CREATED_AT, Some(0)).unwrap() } + } + #[inline] + pub fn kind(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Event::VT_KIND, Some(0)).unwrap() } + } + #[inline] + pub fn tags( + &self, + ) -> Option>> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab.get::>, + >>(Event::VT_TAGS, None) + } + } + #[inline] + pub fn content(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::>(Event::VT_CONTENT, None) + } + } + #[inline] + pub fn sig(&self) -> Option<&'a Fixed64Bytes> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Event::VT_SIG, None) } + } + } + + impl flatbuffers::Verifiable for Event<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, + pos: usize, + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::("id", Self::VT_ID, false)? + .visit_field::("pubkey", Self::VT_PUBKEY, false)? + .visit_field::("created_at", Self::VT_CREATED_AT, false)? + .visit_field::("kind", Self::VT_KIND, false)? + .visit_field::>, + >>("tags", Self::VT_TAGS, false)? + .visit_field::>( + "content", + Self::VT_CONTENT, + false, + )? + .visit_field::("sig", Self::VT_SIG, false)? + .finish(); + Ok(()) + } + } + pub struct EventArgs<'a> { + pub id: Option<&'a Fixed32Bytes>, + pub pubkey: Option<&'a Fixed32Bytes>, + pub created_at: u64, + pub kind: u64, + pub tags: Option< + flatbuffers::WIPOffset>>, + >, + pub content: Option>, + pub sig: Option<&'a Fixed64Bytes>, + } + impl<'a> Default for EventArgs<'a> { + #[inline] + fn default() -> Self { + EventArgs { + id: None, + pubkey: None, + created_at: 0, + kind: 0, + tags: None, + content: None, + sig: None, + } + } + } + + pub struct EventBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, + } + impl<'a: 'b, 'b> EventBuilder<'a, 'b> { + #[inline] + pub fn add_id(&mut self, id: &Fixed32Bytes) { + self.fbb_ + .push_slot_always::<&Fixed32Bytes>(Event::VT_ID, id); + } + #[inline] + pub fn add_pubkey(&mut self, pubkey: &Fixed32Bytes) { + self.fbb_ + .push_slot_always::<&Fixed32Bytes>(Event::VT_PUBKEY, pubkey); + } + #[inline] + pub fn add_created_at(&mut self, created_at: u64) { + self.fbb_ + .push_slot::(Event::VT_CREATED_AT, created_at, 0); + } + #[inline] + pub fn add_kind(&mut self, kind: u64) { + self.fbb_.push_slot::(Event::VT_KIND, kind, 0); + } + #[inline] + pub fn add_tags( + &mut self, + tags: flatbuffers::WIPOffset< + flatbuffers::Vector<'b, flatbuffers::ForwardsUOffset<&'b str>>, + >, + ) { + self.fbb_ + .push_slot_always::>(Event::VT_TAGS, tags); + } + #[inline] + pub fn add_content(&mut self, content: flatbuffers::WIPOffset<&'b str>) { + self.fbb_ + .push_slot_always::>(Event::VT_CONTENT, content); + } + #[inline] + pub fn add_sig(&mut self, sig: &Fixed64Bytes) { + self.fbb_ + .push_slot_always::<&Fixed64Bytes>(Event::VT_SIG, sig); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> EventBuilder<'a, 'b> { + let start = _fbb.start_table(); + EventBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } + } + + impl core::fmt::Debug for Event<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("Event"); + ds.field("id", &self.id()); + ds.field("pubkey", &self.pubkey()); + ds.field("created_at", &self.created_at()); + ds.field("kind", &self.kind()); + ds.field("tags", &self.tags()); + ds.field("content", &self.content()); + ds.field("sig", &self.sig()); + ds.finish() + } + } + #[inline] + /// Verifies that a buffer of bytes contains a `Event` + /// and returns it. + /// Note that verification is still experimental and may not + /// catch every error, or be maximally performant. For the + /// previous, unchecked, behavior use + /// `root_as_event_unchecked`. + pub fn root_as_event(buf: &[u8]) -> Result { + flatbuffers::root::(buf) + } + #[inline] + /// Verifies that a buffer of bytes contains a size prefixed + /// `Event` and returns it. + /// Note that verification is still experimental and may not + /// catch every error, or be maximally performant. For the + /// previous, unchecked, behavior use + /// `size_prefixed_root_as_event_unchecked`. + pub fn size_prefixed_root_as_event( + buf: &[u8], + ) -> Result { + flatbuffers::size_prefixed_root::(buf) + } + #[inline] + /// Verifies, with the given options, that a buffer of bytes + /// contains a `Event` and returns it. + /// Note that verification is still experimental and may not + /// catch every error, or be maximally performant. For the + /// previous, unchecked, behavior use + /// `root_as_event_unchecked`. + pub fn root_as_event_with_opts<'b, 'o>( + opts: &'o flatbuffers::VerifierOptions, + buf: &'b [u8], + ) -> Result, flatbuffers::InvalidFlatbuffer> { + flatbuffers::root_with_opts::>(opts, buf) + } + #[inline] + /// Verifies, with the given verifier options, that a buffer of + /// bytes contains a size prefixed `Event` and returns + /// it. Note that verification is still experimental and may not + /// catch every error, or be maximally performant. For the + /// previous, unchecked, behavior use + /// `root_as_event_unchecked`. + pub fn size_prefixed_root_as_event_with_opts<'b, 'o>( + opts: &'o flatbuffers::VerifierOptions, + buf: &'b [u8], + ) -> Result, flatbuffers::InvalidFlatbuffer> { + flatbuffers::size_prefixed_root_with_opts::>(opts, buf) + } + #[inline] + /// Assumes, without verification, that a buffer of bytes contains a Event and returns it. + /// # Safety + /// Callers must trust the given bytes do indeed contain a valid `Event`. + pub unsafe fn root_as_event_unchecked(buf: &[u8]) -> Event { + flatbuffers::root_unchecked::(buf) + } + #[inline] + /// Assumes, without verification, that a buffer of bytes contains a size prefixed Event and returns it. + /// # Safety + /// Callers must trust the given bytes do indeed contain a valid size prefixed `Event`. + pub unsafe fn size_prefixed_root_as_event_unchecked(buf: &[u8]) -> Event { + flatbuffers::size_prefixed_root_unchecked::(buf) + } + #[inline] + pub fn finish_event_buffer<'a, 'b>( + fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, + root: flatbuffers::WIPOffset>, + ) { + fbb.finish(root, None); + } + + #[inline] + pub fn finish_size_prefixed_event_buffer<'a, 'b>( + fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, + root: flatbuffers::WIPOffset>, + ) { + fbb.finish_size_prefixed(root, None); + } +} // pub mod EventFbs diff --git a/crates/nostr-sdk-fbs/src/lib.rs b/crates/nostr-sdk-fbs/src/lib.rs new file mode 100644 index 000000000..ca18dc077 --- /dev/null +++ b/crates/nostr-sdk-fbs/src/lib.rs @@ -0,0 +1,36 @@ +// Copyright (c) 2022-2023 Yuki Kishimoto +// Distributed under the MIT software license + +//! Nostr SDK Flatbuffers + +use event_generated::event_fbs::{Fixed32Bytes, Fixed64Bytes}; +pub use flatbuffers::FlatBufferBuilder; +use nostr::Event; + +#[allow(unused_imports, dead_code)] +mod event_generated; + +pub use self::event_generated::event_fbs; + +pub fn serialize_event<'a>(fbb: &'a mut FlatBufferBuilder, event: &Event) -> &'a [u8] { + fbb.reset(); + + let id = Fixed32Bytes::new(&event.id.to_bytes()); + let pubkey = Fixed32Bytes::new(&event.pubkey.serialize()); + let sig = Fixed64Bytes::new(event.sig.as_ref()); + let args = event_fbs::EventArgs { + id: Some(&id), + pubkey: Some(&pubkey), + created_at: event.created_at.as_u64(), + kind: event.kind.as_u64(), + tags: None, // TODO + content: None, // TODO + sig: Some(&sig), + }; + + let offset = event_fbs::Event::create(fbb, &args); + + event_fbs::finish_event_buffer(fbb, offset); + + fbb.finished_data() +}