use indexmap::IndexMap;
#[derive(Debug, Clone, PartialEq)]
pub enum GgufValue {
U8(u8),
I8(i8),
U16(u16),
I16(i16),
U32(u32),
I32(i32),
U64(u64),
I64(i64),
F32(f32),
F64(f64),
Bool(bool),
String(String),
Array(Vec<GgufValue>),
}
impl GgufValue {
pub fn as_u64(&self) -> Option<u64> {
match *self {
Self::U8(v) => Some(v as u64),
Self::U16(v) => Some(v as u64),
Self::U32(v) => Some(v as u64),
Self::U64(v) => Some(v),
_ => None,
}
}
pub fn as_u32(&self) -> Option<u32> {
match *self {
Self::U8(v) => Some(v as u32),
Self::U16(v) => Some(v as u32),
Self::U32(v) => Some(v),
Self::U64(v) => u32::try_from(v).ok(),
_ => None,
}
}
pub fn as_i64(&self) -> Option<i64> {
match *self {
Self::I8(v) => Some(v as i64),
Self::I16(v) => Some(v as i64),
Self::I32(v) => Some(v as i64),
Self::I64(v) => Some(v),
_ => None,
}
}
pub fn as_i32(&self) -> Option<i32> {
match *self {
Self::I8(v) => Some(v as i32),
Self::I16(v) => Some(v as i32),
Self::I32(v) => Some(v),
Self::I64(v) => i32::try_from(v).ok(),
_ => None,
}
}
pub fn as_f32(&self) -> Option<f32> {
match *self {
Self::F32(v) => Some(v),
_ => None,
}
}
pub fn as_f64(&self) -> Option<f64> {
match *self {
Self::F32(v) => Some(v as f64),
Self::F64(v) => Some(v),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match *self {
Self::Bool(v) => Some(v),
_ => None,
}
}
pub fn as_str(&self) -> Option<&str> {
match self {
Self::String(v) => Some(v),
_ => None,
}
}
pub fn as_array(&self) -> Option<&[GgufValue]> {
match self {
Self::Array(v) => Some(v),
_ => None,
}
}
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct GgufMetadata(pub(crate) IndexMap<String, GgufValue>);
impl GgufMetadata {
pub(crate) fn new() -> Self {
Self(IndexMap::new())
}
pub fn get(&self, key: &str) -> Option<&GgufValue> {
self.0.get(key)
}
pub fn get_u64(&self, key: &str) -> Option<u64> {
self.get(key)?.as_u64()
}
pub fn get_u32(&self, key: &str) -> Option<u32> {
self.get(key)?.as_u32()
}
pub fn get_i64(&self, key: &str) -> Option<i64> {
self.get(key)?.as_i64()
}
pub fn get_i32(&self, key: &str) -> Option<i32> {
self.get(key)?.as_i32()
}
pub fn get_f32(&self, key: &str) -> Option<f32> {
self.get(key)?.as_f32()
}
pub fn get_f64(&self, key: &str) -> Option<f64> {
self.get(key)?.as_f64()
}
pub fn get_bool(&self, key: &str) -> Option<bool> {
self.get(key)?.as_bool()
}
pub fn get_str(&self, key: &str) -> Option<&str> {
self.get(key)?.as_str()
}
pub fn get_array(&self, key: &str) -> Option<&[GgufValue]> {
self.get(key)?.as_array()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&str, &GgufValue)> {
self.0.iter().map(|(k, v)| (k.as_str(), v))
}
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct ModelMetadata {
pub architecture: Option<String>,
pub name: Option<String>,
pub n_layers: Option<u64>,
pub n_heads: Option<u64>,
pub n_kv_heads: Option<u64>,
pub embedding_length: Option<u64>,
pub feed_forward_length: Option<u64>,
pub context_length: Option<u64>,
pub vocab_size: Option<u64>,
pub rope_theta: Option<f32>,
pub rope_dimension_count: Option<u64>,
pub norm_epsilon: Option<f32>,
pub quantization_version: Option<u32>,
pub file_type: Option<u32>,
pub raw: GgufMetadata,
}