From 4e608443cda0cc90ffb5a145e2a19ea82f7df248 Mon Sep 17 00:00:00 2001 From: gram Date: Mon, 23 Feb 2026 10:32:41 +0100 Subject: [PATCH 1/3] add Me type --- src/net.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/src/net.rs b/src/net.rs index 875cf50..234577a 100644 --- a/src/net.rs +++ b/src/net.rs @@ -1,4 +1,8 @@ -// The peer ID. +pub trait AnyPeer {} + +/// The peer ID. +/// +/// Constructed from [`Peers`] (which is constructed by [`get_peers`]). #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct Peer(pub(crate) u8); @@ -8,14 +12,12 @@ pub struct Peer(pub(crate) u8); impl Peer { /// A combination of all connected peers. pub const COMBINED: Self = Peer(0xFF); -} -impl Peer { /// Dump [`Peer`] as a primitive type (u8). /// /// ## Safety /// - /// See [`Peer::to_u8`]. + /// See [`Peer::into_u8`]. #[must_use] pub unsafe fn from_u8(p: u8) -> Self { Self(p) @@ -36,11 +38,60 @@ impl Peer { } } +impl AnyPeer for Peer {} + +/// The peer representing the current device. +/// +/// Can be compared to [`Peer`] or used to [`get_settings`][crate::get_settings]. +/// +/// **IMPORTANT:** using this type may cause state drift between device in multiplayer. +/// See [the docs](https://docs.fireflyzero.com/dev/net/) for more info. +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct Me(pub(crate) u8); + +impl Me { + /// Convert [`Me`] into primitive type. + /// + /// ## Safety + /// + /// See [`Peer::into_u8`]. + #[must_use] + pub unsafe fn from_u8(p: u8) -> Self { + Self(p) + } + + /// Restore [`Me`] from a primitive type (u8). + /// + /// ## Safety + /// + /// See [`Peer::into_u8`]. + #[must_use] + pub unsafe fn into_u8(self) -> u8 { + self.0 + } +} + +impl AnyPeer for Me {} + +impl PartialEq for Me { + fn eq(&self, other: &Peer) -> bool { + self.0 == other.0 + } +} + +impl PartialEq for Peer { + fn eq(&self, other: &Me) -> bool { + self.0 == other.0 + } +} + /// The list of peers online. /// /// Includes all connected peers as well as the local device. /// /// The order is deterministic between calls and between runs. +/// +/// Constructed by [`get_peers`]. #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub struct Peers(pub(crate) u32); @@ -157,9 +208,9 @@ type Stash = [u8]; /// Get the peer corresponding to the local device. #[must_use] -pub fn get_me() -> Peer { +pub fn get_me() -> Me { let me = unsafe { bindings::get_me() }; - Peer(me as u8) + Me(me as u8) } /// Get the list of peers online. From e9b73e0edf6c4eb6abe8f01f9587c97f28512279 Mon Sep 17 00:00:00 2001 From: gram Date: Mon, 23 Feb 2026 10:41:44 +0100 Subject: [PATCH 2/3] allow Me in get_settings --- src/misc.rs | 8 ++++-- src/net.rs | 71 +++++++++++++++++++++++------------------------------ 2 files changed, 37 insertions(+), 42 deletions(-) diff --git a/src/misc.rs b/src/misc.rs index d189015..263d6ba 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -270,9 +270,13 @@ pub fn get_name(p: Peer, buf: &mut [u8; 16]) -> &str { } /// Get the peer's system settings. +/// +/// **IMPORTANT:** This is the only function that accepts as input not only [`Peer`] +/// but also [`Me`], which might lead to a state drift if used incorrectly. +/// See [the docs](https://docs.fireflyzero.com/dev/net/) for more info. #[must_use] -pub fn get_settings(p: Peer) -> Settings { - let raw = unsafe { bindings::get_settings(u32::from(p.0)) }; +pub fn get_settings(p: P) -> Settings { + let raw = unsafe { bindings::get_settings(u32::from(p.into_u8())) }; let code = [(raw >> 8) as u8, raw as u8]; let language = Language::from_code(code).unwrap_or_default(); let flags = raw >> 16; diff --git a/src/net.rs b/src/net.rs index 234577a..fa319f7 100644 --- a/src/net.rs +++ b/src/net.rs @@ -1,4 +1,25 @@ -pub trait AnyPeer {} +/// A peer obtained either from [`Peers`] ([`get_peers`]) or from [`get_me`]. +pub trait AnyPeer { + /// Dump the peer as a primitive type (u8). + /// + /// ## Safety + /// + /// See [`AnyPeer::into_u8`]. + #[must_use] + unsafe fn from_u8(p: u8) -> Self; + + /// Restore the peer from a primitive type (u8). + /// + /// ## Safety + /// + /// For most applications, [`Peers`], [`Peer`], and [`Me`] types should + /// be considered opaque and agnostic of their internal representation. + /// However, some code interpreters written for Firefly in Rust (firefly-lua) + /// might need the ability to save values on the virtual stack as primitive types, + /// and this is where this function comes in handy. + #[must_use] + unsafe fn into_u8(self) -> u8; +} /// The peer ID. /// @@ -6,73 +27,43 @@ pub trait AnyPeer {} #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct Peer(pub(crate) u8); -/// Represents a specific device (or combination of such). +/// Represents a specific device (or a combination of all devices). /// /// Used for reading and writing state of a device: input, stash, scores, etc. impl Peer { /// A combination of all connected peers. pub const COMBINED: Self = Peer(0xFF); +} - /// Dump [`Peer`] as a primitive type (u8). - /// - /// ## Safety - /// - /// See [`Peer::into_u8`]. - #[must_use] - pub unsafe fn from_u8(p: u8) -> Self { +impl AnyPeer for Peer { + unsafe fn from_u8(p: u8) -> Self { Self(p) } - /// Restore [`Peer`] from a primitive type (u8). - /// - /// ## Safety - /// - /// For most applications, [`Peers`] and [`Peer`] types should be considered - /// opaque and agnostic of their internal representation. - /// However, some code interpreters written for Firefly in Rust - /// might need the ability to save values on virtual stack as primitive types, - /// and this is where this function comes in handy. - #[must_use] - pub unsafe fn into_u8(self) -> u8 { + unsafe fn into_u8(self) -> u8 { self.0 } } -impl AnyPeer for Peer {} - /// The peer representing the current device. /// /// Can be compared to [`Peer`] or used to [`get_settings`][crate::get_settings]. /// -/// **IMPORTANT:** using this type may cause state drift between device in multiplayer. +/// **IMPORTANT:** Using this type may cause state drift between device in multiplayer. /// See [the docs](https://docs.fireflyzero.com/dev/net/) for more info. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct Me(pub(crate) u8); -impl Me { - /// Convert [`Me`] into primitive type. - /// - /// ## Safety - /// - /// See [`Peer::into_u8`]. - #[must_use] - pub unsafe fn from_u8(p: u8) -> Self { +impl AnyPeer for Me { + unsafe fn from_u8(p: u8) -> Self { Self(p) } - /// Restore [`Me`] from a primitive type (u8). - /// - /// ## Safety - /// - /// See [`Peer::into_u8`]. - #[must_use] - pub unsafe fn into_u8(self) -> u8 { + unsafe fn into_u8(self) -> u8 { self.0 } } -impl AnyPeer for Me {} - impl PartialEq for Me { fn eq(&self, other: &Peer) -> bool { self.0 == other.0 From 9b7cf69f14c3290e69ed2fa1ae4b9c1cd11bc1b2 Mon Sep 17 00:00:00 2001 From: gram Date: Mon, 23 Feb 2026 11:37:08 +0100 Subject: [PATCH 3/3] fix docs --- src/net.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net.rs b/src/net.rs index fa319f7..e8fc83c 100644 --- a/src/net.rs +++ b/src/net.rs @@ -1,6 +1,6 @@ /// A peer obtained either from [`Peers`] ([`get_peers`]) or from [`get_me`]. pub trait AnyPeer { - /// Dump the peer as a primitive type (u8). + /// Restore the peer from a primitive type (u8). /// /// ## Safety /// @@ -8,7 +8,7 @@ pub trait AnyPeer { #[must_use] unsafe fn from_u8(p: u8) -> Self; - /// Restore the peer from a primitive type (u8). + /// Dump the peer as a primitive type (u8). /// /// ## Safety ///