Skip to main content

llama_cpp_2/gguf/
mod.rs

1//! Safe wrapper around `gguf_context` for reading GGUF file metadata.
2//!
3//! Provides metadata-only access to GGUF files without loading tensor data.
4//! Useful for inspecting model architecture parameters before loading a model.
5
6use std::ffi::{CStr, CString};
7use std::path::Path;
8use std::ptr::NonNull;
9
10/// A safe wrapper around `gguf_context`.
11///
12/// Opens a GGUF file and parses only the metadata header; tensor weights are
13/// never loaded into memory (`no_alloc = true`).
14#[derive(Debug)]
15pub struct GgufContext {
16    ctx: NonNull<llama_cpp_sys_2::gguf_context>,
17}
18
19impl GgufContext {
20    /// Open a GGUF file and parse its metadata header.
21    ///
22    /// Returns `None` if the path contains a null byte, the file does not
23    /// exist, or the file is not a valid GGUF file.
24    pub fn from_file(path: &Path) -> Option<Self> {
25        let c_path = CString::new(path.to_str()?).ok()?;
26        let params = llama_cpp_sys_2::gguf_init_params {
27            no_alloc: true,
28            ctx: std::ptr::null_mut(),
29        };
30        let ptr = unsafe { llama_cpp_sys_2::gguf_init_from_file(c_path.as_ptr(), params) };
31        Some(Self {
32            ctx: NonNull::new(ptr)?,
33        })
34    }
35
36    /// Total number of key-value pairs in the metadata.
37    pub fn n_kv(&self) -> i64 {
38        unsafe { llama_cpp_sys_2::gguf_get_n_kv(self.ctx.as_ptr()) }
39    }
40
41    /// Find the index of a key by name. Returns `-1` if not found.
42    pub fn find_key(&self, key: &str) -> i64 {
43        let Ok(c_key) = CString::new(key) else {
44            return -1;
45        };
46        unsafe { llama_cpp_sys_2::gguf_find_key(self.ctx.as_ptr(), c_key.as_ptr()) }
47    }
48
49    /// Return the key name at the given index, or `None` if out of range.
50    pub fn key_at(&self, idx: i64) -> Option<&str> {
51        let ptr = unsafe { llama_cpp_sys_2::gguf_get_key(self.ctx.as_ptr(), idx) };
52        if ptr.is_null() {
53            return None;
54        }
55        unsafe { CStr::from_ptr(ptr).to_str().ok() }
56    }
57
58    /// Return the value type of the KV pair at `idx`.
59    pub fn kv_type(&self, idx: i64) -> llama_cpp_sys_2::gguf_type {
60        unsafe { llama_cpp_sys_2::gguf_get_kv_type(self.ctx.as_ptr(), idx) }
61    }
62
63    /// Read a `uint32` value. Panics (inside llama.cpp) if the stored type is
64    /// not `GGUF_TYPE_UINT32` — check `kv_type` first if unsure.
65    pub fn val_u32(&self, idx: i64) -> u32 {
66        unsafe { llama_cpp_sys_2::gguf_get_val_u32(self.ctx.as_ptr(), idx) }
67    }
68
69    /// Read an `int32` value.
70    pub fn val_i32(&self, idx: i64) -> i32 {
71        unsafe { llama_cpp_sys_2::gguf_get_val_i32(self.ctx.as_ptr(), idx) }
72    }
73
74    /// Read a `uint64` value.
75    pub fn val_u64(&self, idx: i64) -> u64 {
76        unsafe { llama_cpp_sys_2::gguf_get_val_u64(self.ctx.as_ptr(), idx) }
77    }
78
79    /// Read a string value. Returns `None` if the pointer is null or not
80    /// valid UTF-8.
81    pub fn val_str(&self, idx: i64) -> Option<&str> {
82        let ptr = unsafe { llama_cpp_sys_2::gguf_get_val_str(self.ctx.as_ptr(), idx) };
83        if ptr.is_null() {
84            return None;
85        }
86        unsafe { CStr::from_ptr(ptr).to_str().ok() }
87    }
88
89    /// Total number of tensors described in the file.
90    pub fn n_tensors(&self) -> i64 {
91        unsafe { llama_cpp_sys_2::gguf_get_n_tensors(self.ctx.as_ptr()) }
92    }
93}
94
95impl Drop for GgufContext {
96    fn drop(&mut self) {
97        unsafe { llama_cpp_sys_2::gguf_free(self.ctx.as_ptr()) }
98    }
99}
100
101#[cfg(test)]
102mod tests;