hurray_core/layout/private_extension.rs
1//! Private extension layout descriptor.
2//!
3//! Tags `0xF0`–`0xFE`. Implementation-private; opaque to all conforming readers
4//! without an out-of-band semantic agreement.
5//! See `docs/spec/memory-layout.md § Extension Layouts`.
6
7use crate::{Error, Result};
8
9/// The inclusive byte range of private-extension layout tags.
10pub const PRIVATE_LAYOUT_TAG_MIN: u8 = 0xF0;
11/// The inclusive upper bound of the private-extension layout tag range.
12pub const PRIVATE_LAYOUT_TAG_MAX: u8 = 0xFE;
13
14/// Descriptor for an implementation-private extension layout.
15///
16/// Tags in `0xF0`–`0xFE` are reserved for implementation-private layouts.
17/// Tensors using these tags MUST NOT be exchanged between independent
18/// implementations unless both parties have agreed on the layout semantics out
19/// of band.
20///
21/// An extension layout descriptor carries:
22/// - an `extension_layout_id` (`uint64`): implementation-defined unique identifier,
23/// - `extension_data` (`Vec<u8>`): opaque layout-specific metadata.
24///
25/// The `Unknown` variant (for unrecognized tags in permissive mode) is
26/// separate; see [`UnknownLayout`].
27///
28/// # Examples
29///
30/// ```
31/// use hurray_core::layout::{LayoutDescriptor, PrivateExtensionLayout};
32///
33/// let layout = LayoutDescriptor::PrivateExtension(
34/// PrivateExtensionLayout::new(0xF0, 0xDEAD_BEEF_CAFE_0001, vec![1, 2, 3]).unwrap(),
35/// );
36/// assert_eq!(layout.tag(), 0xF0);
37/// // buffer_count is None — unknown for private layouts.
38/// assert!(layout.buffer_count().is_none());
39/// ```
40#[derive(Debug, Clone, PartialEq, Eq, Hash)]
41#[non_exhaustive]
42pub struct PrivateExtensionLayout {
43 /// The layout tag byte (`0xF0`–`0xFE`).
44 pub tag: u8,
45
46 /// Implementation-defined unique identifier for this extension layout.
47 pub extension_layout_id: u64,
48
49 /// Opaque layout-specific metadata.
50 pub extension_data: Vec<u8>,
51}
52
53impl PrivateExtensionLayout {
54 /// Creates a new [`PrivateExtensionLayout`], validating that `tag` is in
55 /// the private-extension range `0xF0`–`0xFE`.
56 ///
57 /// # Errors
58 ///
59 /// Returns [`Error::InvalidLayout`] if `tag` is outside `0xF0`–`0xFE`.
60 ///
61 /// # Examples
62 ///
63 /// ```
64 /// use hurray_core::layout::PrivateExtensionLayout;
65 ///
66 /// let p = PrivateExtensionLayout::new(0xF1, 42, vec![0xAB, 0xCD]).unwrap();
67 /// assert_eq!(p.tag, 0xF1);
68 ///
69 /// // Tags outside the private range are rejected.
70 /// assert!(PrivateExtensionLayout::new(0x01, 0, vec![]).is_err());
71 /// assert!(PrivateExtensionLayout::new(0xFF, 0, vec![]).is_err());
72 /// ```
73 pub fn new(tag: u8, extension_layout_id: u64, extension_data: Vec<u8>) -> Result<Self> {
74 if !(PRIVATE_LAYOUT_TAG_MIN..=PRIVATE_LAYOUT_TAG_MAX).contains(&tag) {
75 return Err(Error::InvalidLayout(format!(
76 "private extension layout tag 0x{tag:02X} is outside the valid range \
77 0x{PRIVATE_LAYOUT_TAG_MIN:02X}–0x{PRIVATE_LAYOUT_TAG_MAX:02X}"
78 )));
79 }
80 Ok(Self {
81 tag,
82 extension_layout_id,
83 extension_data,
84 })
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use crate::layout::LayoutDescriptor;
92
93 #[test]
94 fn private_extension_tag_passthrough() {
95 for tag in 0xF0u8..=0xFEu8 {
96 let layout = LayoutDescriptor::PrivateExtension(
97 PrivateExtensionLayout::new(tag, 0, vec![]).unwrap(),
98 );
99 assert_eq!(layout.tag(), tag);
100 }
101 }
102
103 #[test]
104 fn private_extension_buffer_count_is_none() {
105 let layout = LayoutDescriptor::PrivateExtension(
106 PrivateExtensionLayout::new(0xF0, 0, vec![]).unwrap(),
107 );
108 assert!(layout.buffer_count().is_none());
109 }
110
111 #[test]
112 fn rejects_tag_below_range() {
113 // 0xEF is reserved, not private.
114 assert!(matches!(
115 PrivateExtensionLayout::new(0xEF, 0, vec![]),
116 Err(Error::InvalidLayout(_))
117 ));
118 }
119
120 #[test]
121 fn rejects_tag_0xff() {
122 // 0xFF is permanently invalid.
123 assert!(matches!(
124 PrivateExtensionLayout::new(0xFF, 0, vec![]),
125 Err(Error::InvalidLayout(_))
126 ));
127 }
128
129 #[test]
130 fn rejects_core_layout_tag() {
131 assert!(matches!(
132 PrivateExtensionLayout::new(0x01, 0, vec![]),
133 Err(Error::InvalidLayout(_))
134 ));
135 }
136}