use std::fmt;
use std::num::NonZeroU32;
use std::sync::Arc;
use std::sync::atomic::{AtomicU32, Ordering};
use serde::de::Error as DeError;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use uuid::Uuid;
const SESSION_COUNTER_START: u32 = 1;
static SESSION_COUNTER: AtomicU32 = AtomicU32::new(SESSION_COUNTER_START);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct SessionId(NonZeroU32);
impl SessionId {
#[inline]
#[must_use]
pub fn next() -> Self {
loop {
let id = SESSION_COUNTER.fetch_add(1, Ordering::Relaxed);
if let Some(non_zero) = NonZeroU32::new(id) {
return Self(non_zero);
}
}
}
#[inline]
#[must_use]
pub fn from_u32(id: u32) -> Option<Self> {
NonZeroU32::new(id).map(Self)
}
#[inline]
#[must_use]
pub const fn as_u32(&self) -> u32 {
self.0.get()
}
}
impl fmt::Display for SessionId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Serialize for SessionId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u32(self.0.get())
}
}
impl<'de> Deserialize<'de> for SessionId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let id = u32::deserialize(deserializer)?;
NonZeroU32::new(id)
.map(Self)
.ok_or_else(|| DeError::custom("session_id cannot be 0"))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct TabId(NonZeroU32);
impl TabId {
#[inline]
#[must_use]
pub fn new(id: u32) -> Option<Self> {
NonZeroU32::new(id).map(Self)
}
#[inline]
#[must_use]
pub const fn as_u32(&self) -> u32 {
self.0.get()
}
}
impl fmt::Display for TabId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Serialize for TabId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u32(self.0.get())
}
}
impl<'de> Deserialize<'de> for TabId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let id = u32::deserialize(deserializer)?;
NonZeroU32::new(id)
.map(Self)
.ok_or_else(|| DeError::custom("tab_id cannot be 0"))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct FrameId(u64);
impl FrameId {
#[inline]
#[must_use]
pub const fn new(id: u64) -> Self {
Self(id)
}
#[inline]
#[must_use]
pub const fn main() -> Self {
Self(0)
}
#[inline]
#[must_use]
pub const fn is_main(&self) -> bool {
self.0 == 0
}
#[inline]
#[must_use]
pub const fn as_u64(&self) -> u64 {
self.0
}
}
impl Default for FrameId {
#[inline]
fn default() -> Self {
Self::main()
}
}
impl fmt::Display for FrameId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<u64> for FrameId {
#[inline]
fn from(id: u64) -> Self {
Self(id)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct RequestId(Uuid);
impl RequestId {
#[inline]
#[must_use]
pub fn generate() -> Self {
Self(Uuid::new_v4())
}
#[inline]
#[must_use]
pub const fn ready() -> Self {
Self(Uuid::nil())
}
#[inline]
#[must_use]
pub fn is_ready(&self) -> bool {
self.0.is_nil()
}
#[inline]
#[must_use]
pub const fn as_uuid(&self) -> &Uuid {
&self.0
}
}
impl Default for RequestId {
#[inline]
fn default() -> Self {
Self::generate()
}
}
impl fmt::Display for RequestId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl From<Uuid> for RequestId {
#[inline]
fn from(uuid: Uuid) -> Self {
Self(uuid)
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ElementId(Arc<str>);
impl ElementId {
#[inline]
#[must_use]
pub fn new(id: impl Into<Arc<str>>) -> Self {
Self(id.into())
}
#[inline]
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for ElementId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl AsRef<str> for ElementId {
#[inline]
fn as_ref(&self) -> &str {
&self.0
}
}
impl Serialize for ElementId {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.0)
}
}
impl<'de> Deserialize<'de> for ElementId {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(Self(Arc::from(s)))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ScriptId(String);
impl ScriptId {
#[inline]
#[must_use]
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
#[inline]
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for ScriptId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl AsRef<str> for ScriptId {
#[inline]
fn as_ref(&self) -> &str {
&self.0
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SubscriptionId(String);
impl SubscriptionId {
#[inline]
#[must_use]
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
#[inline]
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for SubscriptionId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl AsRef<str> for SubscriptionId {
#[inline]
fn as_ref(&self) -> &str {
&self.0
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct InterceptId(String);
impl InterceptId {
#[inline]
#[must_use]
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
#[inline]
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for InterceptId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl AsRef<str> for InterceptId {
#[inline]
fn as_ref(&self) -> &str {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_session_id_increments() {
let id1 = SessionId::next();
let id2 = SessionId::next();
assert!(id1.as_u32() < id2.as_u32());
}
#[test]
fn test_session_id_display() {
let id = SessionId::next();
let display = id.to_string();
assert!(!display.is_empty());
}
#[test]
fn test_session_id_from_u32() {
assert!(SessionId::from_u32(0).is_none());
assert!(SessionId::from_u32(1).is_some());
assert_eq!(SessionId::from_u32(42).unwrap().as_u32(), 42);
}
#[test]
fn test_tab_id_rejects_zero() {
assert!(TabId::new(0).is_none());
assert!(TabId::new(1).is_some());
}
#[test]
fn test_tab_id_value() {
let tab = TabId::new(42).expect("valid tab id");
assert_eq!(tab.as_u32(), 42);
}
#[test]
fn test_frame_id_main() {
let main = FrameId::main();
assert!(main.is_main());
assert_eq!(main.as_u64(), 0);
}
#[test]
fn test_frame_id_iframe() {
let iframe = FrameId::new(17179869185);
assert!(!iframe.is_main());
assert_eq!(iframe.as_u64(), 17179869185);
}
#[test]
fn test_frame_id_default() {
let default = FrameId::default();
assert!(default.is_main());
}
#[test]
fn test_frame_id_from_u64() {
let frame: FrameId = 123u64.into();
assert_eq!(frame.as_u64(), 123);
}
#[test]
fn test_request_id_ready() {
let ready = RequestId::ready();
assert!(ready.is_ready());
assert!(ready.as_uuid().is_nil());
}
#[test]
fn test_request_id_generated() {
let id = RequestId::generate();
assert!(!id.is_ready());
assert!(!id.as_uuid().is_nil());
}
#[test]
fn test_request_id_uniqueness() {
let id1 = RequestId::generate();
let id2 = RequestId::generate();
assert_ne!(id1, id2);
}
#[test]
fn test_element_id() {
let id = ElementId::new("test-uuid");
assert_eq!(id.as_str(), "test-uuid");
assert_eq!(id.as_ref(), "test-uuid");
assert_eq!(id.to_string(), "test-uuid");
}
#[test]
fn test_script_id() {
let id = ScriptId::new("script-123");
assert_eq!(id.as_str(), "script-123");
}
#[test]
fn test_subscription_id() {
let id = SubscriptionId::new("sub-456");
assert_eq!(id.as_str(), "sub-456");
assert_eq!(id.as_ref(), "sub-456");
}
#[test]
fn test_intercept_id() {
let id = InterceptId::new("intercept-789");
assert_eq!(id.as_str(), "intercept-789");
assert_eq!(id.as_ref(), "intercept-789");
}
#[test]
fn test_serde_session_id() {
let id = SessionId::next();
let json = serde_json::to_string(&id).expect("serialize");
let parsed: SessionId = serde_json::from_str(&json).expect("deserialize");
assert_eq!(id, parsed);
}
#[test]
fn test_serde_tab_id() {
let id = TabId::new(42).expect("valid");
let json = serde_json::to_string(&id).expect("serialize");
let parsed: TabId = serde_json::from_str(&json).expect("deserialize");
assert_eq!(id, parsed);
}
#[test]
fn test_serde_frame_id() {
let id = FrameId::new(12345);
let json = serde_json::to_string(&id).expect("serialize");
let parsed: FrameId = serde_json::from_str(&json).expect("deserialize");
assert_eq!(id, parsed);
}
#[test]
fn test_serde_element_id() {
let id = ElementId::new("elem-uuid");
let json = serde_json::to_string(&id).expect("serialize");
let parsed: ElementId = serde_json::from_str(&json).expect("deserialize");
assert_eq!(id, parsed);
}
}