use crate::__linkme::distributed_slice;
use crate::storage::FramedDomain;
#[derive(Clone, Copy, Debug)]
pub struct DomainRecord {
pub domain: FramedDomain,
pub type_path: &'static str,
}
#[distributed_slice]
pub static STORAGE_DOMAINS: [DomainRecord];
pub fn check_duplicate(records: &[DomainRecord]) -> Option<(usize, usize)> {
for i in 0..records.len() {
for j in (i + 1)..records.len() {
if records[i].domain.as_bytes() == records[j].domain.as_bytes()
&& records[i].type_path != records[j].type_path
{
return Some((i, j));
}
}
}
None
}
pub fn assert_unique_storage_domains() {
let records: &[DomainRecord] = &STORAGE_DOMAINS;
if let Some((i, j)) = check_duplicate(records) {
panic!(
"storage domain collision: {} and {} derive the same storage \
root; set #[storage(domain = \"...\")] on one of them to \
disambiguate",
records[i].type_path, records[j].type_path
);
}
}
#[cfg(test)]
mod tests {
use super::*;
fn rec(d: &'static [u8], t: &'static str) -> DomainRecord {
DomainRecord {
domain: FramedDomain::new(d),
type_path: t,
}
}
#[test]
fn distinct_domains_ok() {
let r = [rec(b"A", "x::A"), rec(b"B", "y::B")];
assert_eq!(check_duplicate(&r), None);
}
#[test]
fn same_domain_different_type_flagged() {
let r = [rec(b"A", "x::A"), rec(b"A", "y::A")];
assert_eq!(check_duplicate(&r), Some((0, 1)));
}
#[test]
fn same_domain_same_type_is_not_a_collision() {
let r = [rec(b"A", "x::A"), rec(b"A", "x::A")];
assert_eq!(check_duplicate(&r), None);
}
}