pub const RELEASE_BINDING_PREFIX: &[u8] = b"CANIC_RELEASE_BUILD_SLOT_V1[";
pub const RELEASE_BINDING_SUFFIX: &[u8] = b"]CANIC_RELEASE_BUILD_SLOT_END";
pub const RELEASE_BINDING_ID_BYTES: usize = 64;
pub const RELEASE_BINDING_BYTES: usize =
RELEASE_BINDING_PREFIX.len() + RELEASE_BINDING_ID_BYTES + RELEASE_BINDING_SUFFIX.len();
#[repr(transparent)]
pub struct EmbeddedReleaseBuildId([u8; RELEASE_BINDING_BYTES]);
impl EmbeddedReleaseBuildId {
#[must_use]
pub const fn new(identity: Option<&str>) -> Self {
let mut bytes = [b'?'; RELEASE_BINDING_BYTES];
let mut index = 0;
while index < RELEASE_BINDING_PREFIX.len() {
bytes[index] = RELEASE_BINDING_PREFIX[index];
index += 1;
}
if let Some(identity) = identity {
let identity = identity.as_bytes();
assert!(identity.len() == RELEASE_BINDING_ID_BYTES);
let mut offset = 0;
while offset < RELEASE_BINDING_ID_BYTES {
let byte = identity[offset];
assert!(byte.is_ascii_digit() || (byte >= b'a' && byte <= b'f'));
bytes[index + offset] = byte;
offset += 1;
}
}
index += RELEASE_BINDING_ID_BYTES;
let mut offset = 0;
while offset < RELEASE_BINDING_SUFFIX.len() {
bytes[index + offset] = RELEASE_BINDING_SUFFIX[offset];
offset += 1;
}
Self(bytes)
}
#[must_use]
pub fn read(&self) -> Option<String> {
let bytes = self
.0
.each_ref()
.map(|byte| unsafe { std::ptr::read_volatile(byte) });
let start = RELEASE_BINDING_PREFIX.len();
let end = start + RELEASE_BINDING_ID_BYTES;
assert_eq!(&bytes[..start], RELEASE_BINDING_PREFIX);
assert_eq!(&bytes[end..], RELEASE_BINDING_SUFFIX);
let identity = &bytes[start..end];
if identity.iter().all(|byte| *byte == b'?') {
return None;
}
assert!(identity.iter().all(u8::is_ascii_hexdigit));
assert!(!identity.iter().any(u8::is_ascii_uppercase));
Some(String::from_utf8(identity.to_vec()).expect("canonical release identity"))
}
}