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