use mlx_native::gguf::GgufFile;
pub const KEY_PRODUCER_VERSION: &str = "hf2q.producer_version";
pub const KEY_SOURCE_SHA256: &str = "hf2q.source_sha256";
pub const KEY_MMPROJ_SHA256: &str = "hf2q.mmproj_sha256";
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Provenance {
Hf2q {
producer_version: String,
source_sha256: String,
mmproj_sha256: Option<String>,
},
External,
}
impl Provenance {
pub fn is_hf2q(&self) -> bool {
matches!(self, Provenance::Hf2q { .. })
}
}
pub trait MetadataLookup {
fn get_string(&self, key: &str) -> Option<&str>;
}
impl MetadataLookup for GgufFile {
fn get_string(&self, key: &str) -> Option<&str> {
self.metadata_string(key)
}
}
impl<S: std::hash::BuildHasher> MetadataLookup for std::collections::HashMap<String, String, S> {
fn get_string(&self, key: &str) -> Option<&str> {
self.get(key).map(|s| s.as_str())
}
}
pub fn detect<M: MetadataLookup + ?Sized>(metadata: &M) -> Provenance {
let producer_version = match metadata.get_string(KEY_PRODUCER_VERSION) {
Some(v) if !v.is_empty() => v.to_string(),
_ => return Provenance::External,
};
let source_sha256 = match metadata.get_string(KEY_SOURCE_SHA256) {
Some(v) if !v.is_empty() => v.to_ascii_lowercase(),
_ => return Provenance::External,
};
let mmproj_sha256 = metadata
.get_string(KEY_MMPROJ_SHA256)
.filter(|v| !v.is_empty())
.map(|v| v.to_ascii_lowercase());
Provenance::Hf2q {
producer_version,
source_sha256,
mmproj_sha256,
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
fn meta(pairs: &[(&str, &str)]) -> HashMap<String, String> {
pairs
.iter()
.map(|(k, v)| ((*k).to_string(), (*v).to_string()))
.collect()
}
#[test]
fn detect_returns_hf2q_when_required_keys_present() {
let m = meta(&[
(KEY_PRODUCER_VERSION, "hf2q 0.1.0"),
(KEY_SOURCE_SHA256, &"a".repeat(64)),
]);
match detect(&m) {
Provenance::Hf2q {
producer_version,
source_sha256,
mmproj_sha256,
} => {
assert_eq!(producer_version, "hf2q 0.1.0");
assert_eq!(source_sha256, "a".repeat(64));
assert_eq!(mmproj_sha256, None);
}
other => panic!("expected Hf2q, got {other:?}"),
}
}
#[test]
fn detect_returns_external_when_keys_absent() {
let m = meta(&[
("general.architecture", "qwen35"),
("general.name", "Qwen3.5-MoE"),
]);
assert_eq!(detect(&m), Provenance::External);
assert!(!detect(&m).is_hf2q());
}
#[test]
fn detect_returns_external_when_partial_keys_present() {
let only_version = meta(&[(KEY_PRODUCER_VERSION, "hf2q 0.1.0")]);
assert_eq!(detect(&only_version), Provenance::External);
let only_sha = meta(&[(KEY_SOURCE_SHA256, &"a".repeat(64))]);
assert_eq!(detect(&only_sha), Provenance::External);
let only_mmproj = meta(&[(KEY_MMPROJ_SHA256, &"b".repeat(64))]);
assert_eq!(detect(&only_mmproj), Provenance::External);
}
#[test]
fn detect_returns_external_when_required_key_is_empty_string() {
let empty_version = meta(&[
(KEY_PRODUCER_VERSION, ""),
(KEY_SOURCE_SHA256, &"a".repeat(64)),
]);
assert_eq!(detect(&empty_version), Provenance::External);
let empty_sha = meta(&[
(KEY_PRODUCER_VERSION, "hf2q 0.1.0"),
(KEY_SOURCE_SHA256, ""),
]);
assert_eq!(detect(&empty_sha), Provenance::External);
}
#[test]
fn detect_extracts_mmproj_sha256_when_present() {
let m = meta(&[
(KEY_PRODUCER_VERSION, "hf2q 0.1.0"),
(KEY_SOURCE_SHA256, &"c".repeat(64)),
(KEY_MMPROJ_SHA256, &"d".repeat(64)),
]);
match detect(&m) {
Provenance::Hf2q { mmproj_sha256, .. } => {
assert_eq!(mmproj_sha256.as_deref(), Some("d".repeat(64).as_str()));
}
other => panic!("expected Hf2q with mmproj, got {other:?}"),
}
}
#[test]
fn detect_treats_empty_mmproj_as_absent() {
let m = meta(&[
(KEY_PRODUCER_VERSION, "hf2q 0.1.0"),
(KEY_SOURCE_SHA256, &"e".repeat(64)),
(KEY_MMPROJ_SHA256, ""),
]);
match detect(&m) {
Provenance::Hf2q { mmproj_sha256, .. } => {
assert_eq!(mmproj_sha256, None);
}
other => panic!("expected Hf2q, got {other:?}"),
}
}
#[test]
fn detect_handles_unicode_in_producer_version() {
let banner = "hf2q 0.1.0 \u{1F4DA}\u{1F680} test-build";
let m = meta(&[
(KEY_PRODUCER_VERSION, banner),
(KEY_SOURCE_SHA256, &"f".repeat(64)),
]);
match detect(&m) {
Provenance::Hf2q {
producer_version, ..
} => {
assert_eq!(producer_version, banner);
}
other => panic!("expected Hf2q, got {other:?}"),
}
}
#[test]
fn detect_handles_uppercase_hex_in_sha256() {
let upper = "A".repeat(64);
let m = meta(&[
(KEY_PRODUCER_VERSION, "hf2q 0.1.0"),
(KEY_SOURCE_SHA256, &upper),
(KEY_MMPROJ_SHA256, &"B".repeat(64)),
]);
match detect(&m) {
Provenance::Hf2q {
source_sha256,
mmproj_sha256,
..
} => {
assert_eq!(source_sha256, "a".repeat(64));
assert_eq!(mmproj_sha256.as_deref(), Some("b".repeat(64).as_str()));
}
other => panic!("expected Hf2q, got {other:?}"),
}
}
#[test]
fn detect_handles_mixed_case_hex_in_sha256() {
let mixed: String = (0..64)
.map(|i| if i % 2 == 0 { 'A' } else { 'b' })
.collect();
let m = meta(&[
(KEY_PRODUCER_VERSION, "hf2q 0.1.0"),
(KEY_SOURCE_SHA256, &mixed),
]);
match detect(&m) {
Provenance::Hf2q { source_sha256, .. } => {
assert!(source_sha256.chars().all(|c| !c.is_ascii_uppercase()));
assert_eq!(source_sha256, mixed.to_ascii_lowercase());
}
other => panic!("expected Hf2q, got {other:?}"),
}
}
#[test]
fn metadata_keys_are_namespaced_under_hf2q() {
assert_eq!(KEY_PRODUCER_VERSION, "hf2q.producer_version");
assert_eq!(KEY_SOURCE_SHA256, "hf2q.source_sha256");
assert_eq!(KEY_MMPROJ_SHA256, "hf2q.mmproj_sha256");
}
}
pub mod source_shard;
pub use source_shard::{compute_source_bundle_sha256, SourceShard};