#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub struct LayerIdentity {
pub layer_id: u16,
pub view_id: Option<u16>,
pub access_unit: Option<u64>,
}
impl LayerIdentity {
pub const WIRE_LEN: usize = 13;
pub const fn new(layer_id: u16) -> Self {
Self {
layer_id,
view_id: None,
access_unit: None,
}
}
pub const fn base() -> Self {
Self::new(0)
}
pub const fn with_view_id(mut self, view_id: u16) -> Self {
self.view_id = Some(view_id);
self
}
pub const fn with_access_unit(mut self, index: u64) -> Self {
self.access_unit = Some(index);
self
}
pub const fn is_base_layer(&self) -> bool {
self.layer_id == 0
}
pub fn to_bytes(&self) -> [u8; Self::WIRE_LEN] {
let mut out = [0u8; Self::WIRE_LEN];
let mut flags = 0u8;
if self.view_id.is_some() {
flags |= 1;
}
if self.access_unit.is_some() {
flags |= 2;
}
out[0] = flags;
out[1..3].copy_from_slice(&self.layer_id.to_le_bytes());
out[3..5].copy_from_slice(&self.view_id.unwrap_or(0).to_le_bytes());
out[5..13].copy_from_slice(&self.access_unit.unwrap_or(0).to_le_bytes());
out
}
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
let b = bytes.get(..Self::WIRE_LEN)?;
let flags = b[0];
let layer_id = u16::from_le_bytes([b[1], b[2]]);
let view_id = (flags & 1 != 0).then(|| u16::from_le_bytes([b[3], b[4]]));
let access_unit = (flags & 2 != 0).then(|| {
let mut au = [0u8; 8];
au.copy_from_slice(&b[5..13]);
u64::from_le_bytes(au)
});
Some(Self {
layer_id,
view_id,
access_unit,
})
}
}
impl std::fmt::Display for LayerIdentity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "layer {}", self.layer_id)?;
if let Some(v) = self.view_id {
write!(f, " view {v}")?;
}
if let Some(au) = self.access_unit {
write!(f, " @au {au}")?;
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub struct LayerInfo {
pub layer_id: u16,
pub view_id: Option<u16>,
pub depends_on: Vec<u16>,
}
impl LayerInfo {
pub fn new(layer_id: u16) -> Self {
Self {
layer_id,
view_id: None,
depends_on: Vec::new(),
}
}
pub fn with_view_id(mut self, view_id: u16) -> Self {
self.view_id = Some(view_id);
self
}
pub fn with_depends_on(mut self, layers: impl Into<Vec<u16>>) -> Self {
self.depends_on = layers.into();
self
}
pub fn is_base_layer(&self) -> bool {
self.layer_id == 0
}
pub fn identity(&self) -> LayerIdentity {
LayerIdentity {
layer_id: self.layer_id,
view_id: self.view_id,
access_unit: None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_identity_is_the_base_layer() {
let id = LayerIdentity::default();
assert_eq!(id, LayerIdentity::base());
assert_eq!(id, LayerIdentity::new(0));
assert!(id.is_base_layer());
assert_eq!(id.layer_id, 0);
assert_eq!(id.view_id, None);
assert_eq!(id.access_unit, None);
assert_eq!(id.to_string(), "layer 0");
}
#[test]
fn builders_set_fields() {
let id = LayerIdentity::new(3).with_view_id(1).with_access_unit(42);
assert_eq!(id.layer_id, 3);
assert_eq!(id.view_id, Some(1));
assert_eq!(id.access_unit, Some(42));
assert!(!id.is_base_layer());
assert_eq!(id.to_string(), "layer 3 view 1 @au 42");
assert_eq!(
LayerIdentity::new(2).with_access_unit(7).to_string(),
"layer 2 @au 7"
);
}
#[test]
fn wire_bytes_round_trip() {
for id in [
LayerIdentity::base(),
LayerIdentity::new(0x1234),
LayerIdentity::new(1).with_view_id(0),
LayerIdentity::new(1).with_view_id(0xBEEF),
LayerIdentity::new(5).with_access_unit(0),
LayerIdentity::new(5).with_access_unit(u64::MAX),
LayerIdentity::new(u16::MAX)
.with_view_id(u16::MAX)
.with_access_unit(0x0102_0304_0506_0708),
] {
let bytes = id.to_bytes();
assert_eq!(LayerIdentity::from_bytes(&bytes), Some(id), "{id}");
}
let b = LayerIdentity::new(0x0201)
.with_view_id(0x0403)
.with_access_unit(0x0C0B_0A09_0807_0605)
.to_bytes();
assert_eq!(b, [3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
assert_eq!(LayerIdentity::new(1).with_view_id(0).to_bytes()[0], 1);
assert_eq!(LayerIdentity::new(1).to_bytes()[0], 0);
}
#[test]
fn wire_bytes_tolerate_extra_and_reject_short() {
let mut long = LayerIdentity::new(9).to_bytes().to_vec();
long.extend_from_slice(&[0xFF; 5]);
assert_eq!(
LayerIdentity::from_bytes(&long),
Some(LayerIdentity::new(9))
);
assert_eq!(LayerIdentity::from_bytes(&long[..12]), None);
assert_eq!(LayerIdentity::from_bytes(&[]), None);
let mut b = LayerIdentity::new(1).to_bytes();
b[0] |= 0xF0;
assert_eq!(LayerIdentity::from_bytes(&b), Some(LayerIdentity::new(1)));
}
#[test]
fn layer_info_builders_and_identity() {
let base = LayerInfo::new(0);
assert!(base.is_base_layer());
assert_eq!(base, LayerInfo::default());
assert!(base.depends_on.is_empty());
assert_eq!(base.identity(), LayerIdentity::base());
let right = LayerInfo::new(1).with_view_id(1).with_depends_on([0u16]);
assert_eq!(right.layer_id, 1);
assert_eq!(right.view_id, Some(1));
assert_eq!(right.depends_on, vec![0]);
assert_eq!(right.identity(), LayerIdentity::new(1).with_view_id(1));
let quality = LayerInfo::new(2).with_depends_on(vec![0, 1]);
assert_eq!(quality.depends_on, vec![0, 1]);
assert_eq!(quality.clone(), quality);
}
}