Skip to main content

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}