llama_cpp_bindings/context/
session.rs1use std::ffi::CString;
2use std::path::Path;
3
4use crate::context::LlamaContext;
5use crate::context::llama_state_seq_flags::LlamaStateSeqFlags;
6use crate::context::load_seq_state_error::LoadSeqStateError;
7use crate::context::load_session_error::LoadSessionError;
8use crate::context::save_seq_state_error::SaveSeqStateError;
9use crate::context::save_session_error::SaveSessionError;
10use crate::token::LlamaToken;
11
12fn process_session_load_result(
13 success: bool,
14 n_out: usize,
15 max_tokens: usize,
16 mut tokens: Vec<LlamaToken>,
17) -> Result<Vec<LlamaToken>, LoadSessionError> {
18 if !success {
19 return Err(LoadSessionError::FailedToLoad);
20 }
21
22 if n_out > max_tokens {
23 return Err(LoadSessionError::InsufficientMaxLength { n_out, max_tokens });
24 }
25
26 unsafe { tokens.set_len(n_out) };
27
28 Ok(tokens)
29}
30
31fn process_seq_load_result(
32 bytes_read: usize,
33 n_out: usize,
34 max_tokens: usize,
35 mut tokens: Vec<LlamaToken>,
36) -> Result<(Vec<LlamaToken>, usize), LoadSeqStateError> {
37 if bytes_read == 0 {
38 return Err(LoadSeqStateError::FailedToLoad);
39 }
40
41 if n_out > max_tokens {
42 return Err(LoadSeqStateError::InsufficientMaxLength { n_out, max_tokens });
43 }
44
45 unsafe { tokens.set_len(n_out) };
46
47 Ok((tokens, bytes_read))
48}
49
50impl LlamaContext<'_> {
51 pub fn state_save_file(
55 &self,
56 path_session: impl AsRef<Path>,
57 tokens: &[LlamaToken],
58 ) -> Result<(), SaveSessionError> {
59 let path = path_session.as_ref();
60 let path = path
61 .to_str()
62 .ok_or_else(|| SaveSessionError::PathToStrError(path.to_path_buf()))?;
63
64 let cstr = CString::new(path)?;
65
66 if unsafe {
67 llama_cpp_bindings_sys::llama_state_save_file(
68 self.context.as_ptr(),
69 cstr.as_ptr(),
70 tokens
71 .as_ptr()
72 .cast::<llama_cpp_bindings_sys::llama_token>(),
73 tokens.len(),
74 )
75 } {
76 Ok(())
77 } else {
78 Err(SaveSessionError::FailedToSave)
79 }
80 }
81
82 pub fn state_load_file(
86 &mut self,
87 path_session: impl AsRef<Path>,
88 max_tokens: usize,
89 ) -> Result<Vec<LlamaToken>, LoadSessionError> {
90 let path = path_session.as_ref();
91 let path = path
92 .to_str()
93 .ok_or_else(|| LoadSessionError::PathToStrError(path.to_path_buf()))?;
94
95 let cstr = CString::new(path)?;
96 let mut tokens: Vec<LlamaToken> = Vec::with_capacity(max_tokens);
97 let mut n_out = 0;
98
99 let tokens_out = tokens
101 .as_mut_ptr()
102 .cast::<llama_cpp_bindings_sys::llama_token>();
103
104 let success = unsafe {
105 llama_cpp_bindings_sys::llama_state_load_file(
106 self.context.as_ptr(),
107 cstr.as_ptr(),
108 tokens_out,
109 max_tokens,
110 &raw mut n_out,
111 )
112 };
113 process_session_load_result(success, n_out, max_tokens, tokens)
114 }
115
116 pub fn state_seq_save_file(
121 &self,
122 filepath: impl AsRef<Path>,
123 seq_id: i32,
124 tokens: &[LlamaToken],
125 ) -> Result<usize, SaveSeqStateError> {
126 let path = filepath.as_ref();
127 let path = path
128 .to_str()
129 .ok_or_else(|| SaveSeqStateError::PathToStrError(path.to_path_buf()))?;
130
131 let cstr = CString::new(path)?;
132
133 let bytes_written = unsafe {
134 llama_cpp_bindings_sys::llama_state_seq_save_file(
135 self.context.as_ptr(),
136 cstr.as_ptr(),
137 seq_id,
138 tokens
139 .as_ptr()
140 .cast::<llama_cpp_bindings_sys::llama_token>(),
141 tokens.len(),
142 )
143 };
144
145 if bytes_written == 0 {
146 Err(SaveSeqStateError::FailedToSave)
147 } else {
148 Ok(bytes_written)
149 }
150 }
151
152 pub fn state_seq_load_file(
157 &mut self,
158 filepath: impl AsRef<Path>,
159 dest_seq_id: i32,
160 max_tokens: usize,
161 ) -> Result<(Vec<LlamaToken>, usize), LoadSeqStateError> {
162 let path = filepath.as_ref();
163 let path = path
164 .to_str()
165 .ok_or_else(|| LoadSeqStateError::PathToStrError(path.to_path_buf()))?;
166
167 let cstr = CString::new(path)?;
168 let mut tokens: Vec<LlamaToken> = Vec::with_capacity(max_tokens);
169 let mut n_out = 0;
170
171 let tokens_out = tokens
173 .as_mut_ptr()
174 .cast::<llama_cpp_bindings_sys::llama_token>();
175
176 let bytes_read = unsafe {
177 llama_cpp_bindings_sys::llama_state_seq_load_file(
178 self.context.as_ptr(),
179 cstr.as_ptr(),
180 dest_seq_id,
181 tokens_out,
182 max_tokens,
183 &raw mut n_out,
184 )
185 };
186
187 process_seq_load_result(bytes_read, n_out, max_tokens, tokens)
188 }
189
190 #[must_use]
191 pub fn get_state_size(&self) -> usize {
192 unsafe { llama_cpp_bindings_sys::llama_state_get_size(self.context.as_ptr()) }
193 }
194
195 pub unsafe fn copy_state_data(&self, dest: &mut [u8]) -> usize {
199 unsafe {
200 llama_cpp_bindings_sys::llama_state_get_data(
201 self.context.as_ptr(),
202 dest.as_mut_ptr(),
203 dest.len(),
204 )
205 }
206 }
207
208 pub unsafe fn set_state_data(&mut self, src: &[u8]) -> usize {
214 unsafe {
215 llama_cpp_bindings_sys::llama_state_set_data(
216 self.context.as_ptr(),
217 src.as_ptr(),
218 src.len(),
219 )
220 }
221 }
222
223 #[must_use]
224 pub fn state_seq_get_size_ext(&self, seq_id: i32, flags: &LlamaStateSeqFlags) -> usize {
225 unsafe {
226 llama_cpp_bindings_sys::llama_state_seq_get_size_ext(
227 self.context.as_ptr(),
228 seq_id,
229 flags.bits(),
230 )
231 }
232 }
233
234 pub unsafe fn state_seq_get_data_ext(
238 &self,
239 dest: &mut [u8],
240 seq_id: i32,
241 flags: &LlamaStateSeqFlags,
242 ) -> usize {
243 unsafe {
244 llama_cpp_bindings_sys::llama_state_seq_get_data_ext(
245 self.context.as_ptr(),
246 dest.as_mut_ptr(),
247 dest.len(),
248 seq_id,
249 flags.bits(),
250 )
251 }
252 }
253
254 pub unsafe fn state_seq_set_data_ext(
259 &mut self,
260 src: &[u8],
261 dest_seq_id: i32,
262 flags: &LlamaStateSeqFlags,
263 ) -> usize {
264 unsafe {
265 llama_cpp_bindings_sys::llama_state_seq_set_data_ext(
266 self.context.as_ptr(),
267 src.as_ptr(),
268 src.len(),
269 dest_seq_id,
270 flags.bits(),
271 )
272 }
273 }
274}
275
276#[cfg(test)]
277mod unit_tests {
278 use crate::token::LlamaToken;
279
280 use crate::context::load_seq_state_error::LoadSeqStateError;
281 use crate::context::load_session_error::LoadSessionError;
282
283 use super::{process_seq_load_result, process_session_load_result};
284
285 #[test]
286 fn session_load_success_within_bounds() {
287 let tokens = vec![LlamaToken::new(0); 100];
288 let result = process_session_load_result(true, 10, 100, tokens);
289
290 assert!(result.is_ok());
291 assert_eq!(result.unwrap().len(), 10);
292 }
293
294 #[test]
295 fn session_load_fails_when_not_successful() {
296 let tokens = vec![LlamaToken::new(0); 100];
297 let result = process_session_load_result(false, 0, 100, tokens);
298
299 assert_eq!(result, Err(LoadSessionError::FailedToLoad));
300 }
301
302 #[test]
303 fn session_load_fails_when_n_out_exceeds_max() {
304 let tokens = vec![LlamaToken::new(0); 100];
305 let result = process_session_load_result(true, 101, 100, tokens);
306
307 assert_eq!(
308 result,
309 Err(LoadSessionError::InsufficientMaxLength {
310 n_out: 101,
311 max_tokens: 100,
312 })
313 );
314 }
315
316 #[test]
317 fn seq_load_success_within_bounds() {
318 let tokens = vec![LlamaToken::new(0); 100];
319 let result = process_seq_load_result(42, 10, 100, tokens);
320
321 assert!(result.is_ok());
322 let (loaded, bytes) = result.unwrap();
323 assert_eq!(loaded.len(), 10);
324 assert_eq!(bytes, 42);
325 }
326
327 #[test]
328 fn seq_load_fails_when_zero_bytes_read() {
329 let tokens = vec![LlamaToken::new(0); 100];
330 let result = process_seq_load_result(0, 0, 100, tokens);
331
332 assert_eq!(result, Err(LoadSeqStateError::FailedToLoad));
333 }
334
335 #[test]
336 fn seq_load_fails_when_n_out_exceeds_max() {
337 let tokens = vec![LlamaToken::new(0); 100];
338 let result = process_seq_load_result(42, 101, 100, tokens);
339
340 assert_eq!(
341 result,
342 Err(LoadSeqStateError::InsufficientMaxLength {
343 n_out: 101,
344 max_tokens: 100,
345 })
346 );
347 }
348}