1use std::fmt;
40use std::num::NonZeroU32;
41use std::sync::atomic::{AtomicU32, Ordering};
42
43use serde::de::Error as DeError;
44use serde::{Deserialize, Deserializer, Serialize, Serializer};
45use uuid::Uuid;
46
47const SESSION_COUNTER_START: u32 = 1;
53
54static SESSION_COUNTER: AtomicU32 = AtomicU32::new(SESSION_COUNTER_START);
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
78pub struct SessionId(NonZeroU32);
79
80impl SessionId {
81 #[inline]
90 #[must_use]
91 pub fn next() -> Self {
92 let id = SESSION_COUNTER.fetch_add(1, Ordering::Relaxed);
93
94 let non_zero =
97 NonZeroU32::new(id).expect("session counter overflow - this is a bug, please report");
98
99 Self(non_zero)
100 }
101
102 #[inline]
110 #[must_use]
111 pub fn from_u32(id: u32) -> Option<Self> {
112 NonZeroU32::new(id).map(Self)
113 }
114
115 #[inline]
117 #[must_use]
118 pub const fn as_u32(&self) -> u32 {
119 self.0.get()
120 }
121}
122
123impl fmt::Display for SessionId {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 write!(f, "{}", self.0)
126 }
127}
128
129impl Serialize for SessionId {
130 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
131 where
132 S: Serializer,
133 {
134 serializer.serialize_u32(self.0.get())
135 }
136}
137
138impl<'de> Deserialize<'de> for SessionId {
139 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
140 where
141 D: Deserializer<'de>,
142 {
143 let id = u32::deserialize(deserializer)?;
144 NonZeroU32::new(id)
145 .map(Self)
146 .ok_or_else(|| DeError::custom("session_id cannot be 0"))
147 }
148}
149
150#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
168pub struct TabId(NonZeroU32);
169
170impl TabId {
171 #[inline]
181 #[must_use]
182 pub fn new(id: u32) -> Option<Self> {
183 NonZeroU32::new(id).map(Self)
184 }
185
186 #[inline]
188 #[must_use]
189 pub const fn as_u32(&self) -> u32 {
190 self.0.get()
191 }
192}
193
194impl fmt::Display for TabId {
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 write!(f, "{}", self.0)
197 }
198}
199
200impl Serialize for TabId {
201 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
202 where
203 S: Serializer,
204 {
205 serializer.serialize_u32(self.0.get())
206 }
207}
208
209impl<'de> Deserialize<'de> for TabId {
210 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
211 where
212 D: Deserializer<'de>,
213 {
214 let id = u32::deserialize(deserializer)?;
215 NonZeroU32::new(id)
216 .map(Self)
217 .ok_or_else(|| DeError::custom("tab_id cannot be 0"))
218 }
219}
220
221#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
242pub struct FrameId(u64);
243
244impl FrameId {
245 #[inline]
247 #[must_use]
248 pub const fn new(id: u64) -> Self {
249 Self(id)
250 }
251
252 #[inline]
254 #[must_use]
255 pub const fn main() -> Self {
256 Self(0)
257 }
258
259 #[inline]
261 #[must_use]
262 pub const fn is_main(&self) -> bool {
263 self.0 == 0
264 }
265
266 #[inline]
268 #[must_use]
269 pub const fn as_u64(&self) -> u64 {
270 self.0
271 }
272}
273
274impl Default for FrameId {
275 #[inline]
276 fn default() -> Self {
277 Self::main()
278 }
279}
280
281impl fmt::Display for FrameId {
282 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283 write!(f, "{}", self.0)
284 }
285}
286
287impl From<u64> for FrameId {
288 #[inline]
289 fn from(id: u64) -> Self {
290 Self(id)
291 }
292}
293
294#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
317pub struct RequestId(Uuid);
318
319impl RequestId {
320 #[inline]
322 #[must_use]
323 pub fn generate() -> Self {
324 Self(Uuid::new_v4())
325 }
326
327 #[inline]
331 #[must_use]
332 pub const fn ready() -> Self {
333 Self(Uuid::nil())
334 }
335
336 #[inline]
338 #[must_use]
339 pub fn is_ready(&self) -> bool {
340 self.0.is_nil()
341 }
342
343 #[inline]
345 #[must_use]
346 pub const fn as_uuid(&self) -> &Uuid {
347 &self.0
348 }
349}
350
351impl Default for RequestId {
352 #[inline]
353 fn default() -> Self {
354 Self::generate()
355 }
356}
357
358impl fmt::Display for RequestId {
359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 fmt::Display::fmt(&self.0, f)
361 }
362}
363
364impl From<Uuid> for RequestId {
365 #[inline]
366 fn from(uuid: Uuid) -> Self {
367 Self(uuid)
368 }
369}
370
371#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
387pub struct ElementId(String);
388
389impl ElementId {
390 #[inline]
392 #[must_use]
393 pub fn new(id: impl Into<String>) -> Self {
394 Self(id.into())
395 }
396
397 #[inline]
399 #[must_use]
400 pub fn as_str(&self) -> &str {
401 &self.0
402 }
403}
404
405impl fmt::Display for ElementId {
406 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
407 fmt::Display::fmt(&self.0, f)
408 }
409}
410
411impl AsRef<str> for ElementId {
412 #[inline]
413 fn as_ref(&self) -> &str {
414 &self.0
415 }
416}
417
418#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
427pub struct ScriptId(String);
428
429impl ScriptId {
430 #[inline]
432 #[must_use]
433 pub fn new(id: impl Into<String>) -> Self {
434 Self(id.into())
435 }
436
437 #[inline]
439 #[must_use]
440 pub fn as_str(&self) -> &str {
441 &self.0
442 }
443}
444
445impl fmt::Display for ScriptId {
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 fmt::Display::fmt(&self.0, f)
448 }
449}
450
451impl AsRef<str> for ScriptId {
452 #[inline]
453 fn as_ref(&self) -> &str {
454 &self.0
455 }
456}
457
458#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
467pub struct SubscriptionId(String);
468
469impl SubscriptionId {
470 #[inline]
472 #[must_use]
473 pub fn new(id: impl Into<String>) -> Self {
474 Self(id.into())
475 }
476
477 #[inline]
479 #[must_use]
480 pub fn as_str(&self) -> &str {
481 &self.0
482 }
483}
484
485impl fmt::Display for SubscriptionId {
486 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
487 fmt::Display::fmt(&self.0, f)
488 }
489}
490
491impl AsRef<str> for SubscriptionId {
492 #[inline]
493 fn as_ref(&self) -> &str {
494 &self.0
495 }
496}
497
498#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
507pub struct InterceptId(String);
508
509impl InterceptId {
510 #[inline]
512 #[must_use]
513 pub fn new(id: impl Into<String>) -> Self {
514 Self(id.into())
515 }
516
517 #[inline]
519 #[must_use]
520 pub fn as_str(&self) -> &str {
521 &self.0
522 }
523}
524
525impl fmt::Display for InterceptId {
526 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
527 fmt::Display::fmt(&self.0, f)
528 }
529}
530
531impl AsRef<str> for InterceptId {
532 #[inline]
533 fn as_ref(&self) -> &str {
534 &self.0
535 }
536}
537
538#[cfg(test)]
543mod tests {
544 use super::*;
545
546 #[test]
547 fn test_session_id_increments() {
548 let id1 = SessionId::next();
549 let id2 = SessionId::next();
550 assert!(id1.as_u32() < id2.as_u32());
551 }
552
553 #[test]
554 fn test_session_id_display() {
555 let id = SessionId::next();
556 let display = id.to_string();
557 assert!(!display.is_empty());
558 }
559
560 #[test]
561 fn test_session_id_from_u32() {
562 assert!(SessionId::from_u32(0).is_none());
563 assert!(SessionId::from_u32(1).is_some());
564 assert_eq!(SessionId::from_u32(42).unwrap().as_u32(), 42);
565 }
566
567 #[test]
568 fn test_tab_id_rejects_zero() {
569 assert!(TabId::new(0).is_none());
570 assert!(TabId::new(1).is_some());
571 }
572
573 #[test]
574 fn test_tab_id_value() {
575 let tab = TabId::new(42).expect("valid tab id");
576 assert_eq!(tab.as_u32(), 42);
577 }
578
579 #[test]
580 fn test_frame_id_main() {
581 let main = FrameId::main();
582 assert!(main.is_main());
583 assert_eq!(main.as_u64(), 0);
584 }
585
586 #[test]
587 fn test_frame_id_iframe() {
588 let iframe = FrameId::new(17179869185);
589 assert!(!iframe.is_main());
590 assert_eq!(iframe.as_u64(), 17179869185);
591 }
592
593 #[test]
594 fn test_frame_id_default() {
595 let default = FrameId::default();
596 assert!(default.is_main());
597 }
598
599 #[test]
600 fn test_frame_id_from_u64() {
601 let frame: FrameId = 123u64.into();
602 assert_eq!(frame.as_u64(), 123);
603 }
604
605 #[test]
606 fn test_request_id_ready() {
607 let ready = RequestId::ready();
608 assert!(ready.is_ready());
609 assert!(ready.as_uuid().is_nil());
610 }
611
612 #[test]
613 fn test_request_id_generated() {
614 let id = RequestId::generate();
615 assert!(!id.is_ready());
616 assert!(!id.as_uuid().is_nil());
617 }
618
619 #[test]
620 fn test_request_id_uniqueness() {
621 let id1 = RequestId::generate();
622 let id2 = RequestId::generate();
623 assert_ne!(id1, id2);
624 }
625
626 #[test]
627 fn test_element_id() {
628 let id = ElementId::new("test-uuid");
629 assert_eq!(id.as_str(), "test-uuid");
630 assert_eq!(id.as_ref(), "test-uuid");
631 assert_eq!(id.to_string(), "test-uuid");
632 }
633
634 #[test]
635 fn test_script_id() {
636 let id = ScriptId::new("script-123");
637 assert_eq!(id.as_str(), "script-123");
638 }
639
640 #[test]
641 fn test_subscription_id() {
642 let id = SubscriptionId::new("sub-456");
643 assert_eq!(id.as_str(), "sub-456");
644 assert_eq!(id.as_ref(), "sub-456");
645 }
646
647 #[test]
648 fn test_intercept_id() {
649 let id = InterceptId::new("intercept-789");
650 assert_eq!(id.as_str(), "intercept-789");
651 assert_eq!(id.as_ref(), "intercept-789");
652 }
653
654 #[test]
655 fn test_serde_session_id() {
656 let id = SessionId::next();
657 let json = serde_json::to_string(&id).expect("serialize");
658 let parsed: SessionId = serde_json::from_str(&json).expect("deserialize");
659 assert_eq!(id, parsed);
660 }
661
662 #[test]
663 fn test_serde_tab_id() {
664 let id = TabId::new(42).expect("valid");
665 let json = serde_json::to_string(&id).expect("serialize");
666 let parsed: TabId = serde_json::from_str(&json).expect("deserialize");
667 assert_eq!(id, parsed);
668 }
669
670 #[test]
671 fn test_serde_frame_id() {
672 let id = FrameId::new(12345);
673 let json = serde_json::to_string(&id).expect("serialize");
674 let parsed: FrameId = serde_json::from_str(&json).expect("deserialize");
675 assert_eq!(id, parsed);
676 }
677
678 #[test]
679 fn test_serde_element_id() {
680 let id = ElementId::new("elem-uuid");
681 let json = serde_json::to_string(&id).expect("serialize");
682 let parsed: ElementId = serde_json::from_str(&json).expect("deserialize");
683 assert_eq!(id, parsed);
684 }
685}