ik_llama_cpp_2/context/session.rs
1//! utilities for working with session files
2
3use crate::context::LlamaContext;
4use crate::token::LlamaToken;
5use std::ffi::{CString, NulError};
6use std::fmt::{Debug, Formatter};
7use std::path::{Path, PathBuf};
8
9/// Flags for state sequence operations.
10///
11/// These flags control what parts of the state are included when saving/restoring
12/// sequence state.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct LlamaStateSeqFlags(pub(crate) ik_llama_cpp_sys::llama_state_seq_flags);
15
16impl LlamaStateSeqFlags {
17 /// Work only with partial states, such as SWA KV cache or recurrent cache (e.g. Mamba).
18 ///
19 /// This flag is useful when you only want to save/restore the recurrent state
20 /// without affecting the KV cache.
21 pub const PARTIAL_ONLY: LlamaStateSeqFlags = LlamaStateSeqFlags(1);
22
23 /// Keep the copied data on device (GPU) memory rather than host.
24 ///
25 /// Getting the state for a `seq_id` with this flag invalidates all
26 /// prior states obtained for that `seq_id` with this flag set.
27 pub const ON_DEVICE: LlamaStateSeqFlags = LlamaStateSeqFlags(2);
28
29 /// Create an empty flags set.
30 pub const fn empty() -> LlamaStateSeqFlags {
31 LlamaStateSeqFlags(0)
32 }
33
34 /// Get the raw flags value.
35 pub const fn bits(&self) -> u32 {
36 self.0
37 }
38
39 /// Construct from raw bits.
40 pub const fn from_bits(bits: u32) -> LlamaStateSeqFlags {
41 LlamaStateSeqFlags(bits)
42 }
43
44 /// Check if a flag is set.
45 pub const fn contains(&self, other: LlamaStateSeqFlags) -> bool {
46 (self.0 & other.0) != 0
47 }
48}
49
50impl Default for LlamaStateSeqFlags {
51 fn default() -> Self {
52 Self::empty()
53 }
54}
55
56impl std::ops::BitOr for LlamaStateSeqFlags {
57 type Output = Self;
58 fn bitor(self, other: Self) -> Self {
59 Self(self.0 | other.0)
60 }
61}
62
63/// Errors from the sequence-state save/restore API.
64///
65/// Module-local mirror of the anchor crate's `crate::StateSeqError`, which
66/// lives in the crate root there; kept local here so this module compiles
67/// independently.
68#[derive(Debug, Eq, PartialEq, thiserror::Error)]
69pub enum StateSeqError {
70 /// llama.cpp read or wrote a different number of bytes than expected.
71 #[error("state seq size mismatch: expected {expected}, actual {actual}")]
72 SizeMismatch {
73 /// Number of bytes the caller expected to transfer.
74 expected: usize,
75 /// Number of bytes llama.cpp actually transferred.
76 actual: usize,
77 },
78}
79
80/// Failed to save a sequence state file
81#[derive(Debug, Eq, PartialEq, thiserror::Error)]
82pub enum SaveSeqStateError {
83 /// llama.cpp failed to save the sequence state file
84 #[error("Failed to save sequence state file")]
85 FailedToSave,
86
87 /// null byte in string
88 #[error("null byte in string {0}")]
89 NullError(#[from] NulError),
90
91 /// failed to convert path to str
92 #[error("failed to convert path {0} to str")]
93 PathToStrError(PathBuf),
94}
95
96/// Failed to load a sequence state file
97#[derive(Debug, Eq, PartialEq, thiserror::Error)]
98pub enum LoadSeqStateError {
99 /// llama.cpp failed to load the sequence state file
100 #[error("Failed to load sequence state file")]
101 FailedToLoad,
102
103 /// null byte in string
104 #[error("null byte in string {0}")]
105 NullError(#[from] NulError),
106
107 /// failed to convert path to str
108 #[error("failed to convert path {0} to str")]
109 PathToStrError(PathBuf),
110
111 /// Insufficient max length
112 #[error("max_length is not large enough to hold {n_out} (was {max_tokens})")]
113 InsufficientMaxLength {
114 /// The length of the loaded sequence
115 n_out: usize,
116 /// The maximum length
117 max_tokens: usize,
118 },
119}
120
121/// Failed to save a Session file
122#[derive(Debug, Eq, PartialEq, thiserror::Error)]
123pub enum SaveSessionError {
124 /// llama.cpp failed to save the session file
125 #[error("Failed to save session file")]
126 FailedToSave,
127
128 /// null byte in string
129 #[error("null byte in string {0}")]
130 NullError(#[from] NulError),
131
132 /// failed to convert path to str
133 #[error("failed to convert path {0} to str")]
134 PathToStrError(PathBuf),
135}
136
137/// Failed to load a Session file
138#[derive(Debug, Eq, PartialEq, thiserror::Error)]
139pub enum LoadSessionError {
140 /// llama.cpp failed to load the session file
141 #[error("Failed to load session file")]
142 FailedToLoad,
143
144 /// null byte in string
145 #[error("null byte in string {0}")]
146 NullError(#[from] NulError),
147
148 /// failed to convert path to str
149 #[error("failed to convert path {0} to str")]
150 PathToStrError(PathBuf),
151
152 /// Insufficient max length
153 #[error("max_length is not large enough to hold {n_out} (was {max_tokens})")]
154 InsufficientMaxLength {
155 /// The length of the session file
156 n_out: usize,
157 /// The maximum length
158 max_tokens: usize,
159 },
160}
161
162impl LlamaContext<'_> {
163 /// Save the current session to a file.
164 ///
165 /// # Parameters
166 ///
167 /// * `path_session` - The file to save to.
168 /// * `tokens` - The tokens to associate the session with. This should be a prefix of a sequence of tokens that the context has processed, so that the relevant KV caches are already filled.
169 ///
170 /// # Errors
171 ///
172 /// Fails if the path is not a valid utf8, is not a valid c string, or llama.cpp fails to save the session file.
173 #[deprecated(since = "0.1.136", note = "Use `state_save_file` instead")]
174 pub fn save_session_file(
175 &self,
176 path_session: impl AsRef<Path>,
177 tokens: &[LlamaToken],
178 ) -> Result<(), SaveSessionError> {
179 let path = path_session.as_ref();
180 let path = path
181 .to_str()
182 .ok_or_else(|| SaveSessionError::PathToStrError(path.to_path_buf()))?;
183
184 let cstr = CString::new(path)?;
185
186 if unsafe {
187 ik_llama_cpp_sys::llama_save_session_file(
188 self.context.as_ptr(),
189 cstr.as_ptr(),
190 tokens.as_ptr().cast::<ik_llama_cpp_sys::llama_token>(),
191 tokens.len(),
192 )
193 } {
194 Ok(())
195 } else {
196 Err(SaveSessionError::FailedToSave)
197 }
198 }
199 /// Load a session file into the current context.
200 ///
201 /// You still need to pass the returned tokens to the context for inference to work. What this function buys you is that the KV caches are already filled with the relevant data.
202 ///
203 /// # Parameters
204 ///
205 /// * `path_session` - The file to load from. It must be a session file from a compatible context, otherwise the function will error.
206 /// * `max_tokens` - The maximum token length of the loaded session. If the session was saved with a longer length, the function will error.
207 ///
208 /// # Errors
209 ///
210 /// Fails if the path is not a valid utf8, is not a valid c string, or llama.cpp fails to load the session file. (e.g. the file does not exist, is not a session file, etc.)
211 #[deprecated(since = "0.1.136", note = "Use `state_load_file` instead")]
212 pub fn load_session_file(
213 &mut self,
214 path_session: impl AsRef<Path>,
215 max_tokens: usize,
216 ) -> Result<Vec<LlamaToken>, LoadSessionError> {
217 let path = path_session.as_ref();
218 let path = path
219 .to_str()
220 .ok_or(LoadSessionError::PathToStrError(path.to_path_buf()))?;
221
222 let cstr = CString::new(path)?;
223 let mut tokens: Vec<LlamaToken> = Vec::with_capacity(max_tokens);
224 let mut n_out = 0;
225
226 // SAFETY: cast is valid as LlamaToken is repr(transparent)
227 let tokens_out = tokens.as_mut_ptr().cast::<ik_llama_cpp_sys::llama_token>();
228
229 let load_session_success = unsafe {
230 ik_llama_cpp_sys::llama_load_session_file(
231 self.context.as_ptr(),
232 cstr.as_ptr(),
233 tokens_out,
234 max_tokens,
235 &mut n_out,
236 )
237 };
238 if load_session_success {
239 if n_out > max_tokens {
240 return Err(LoadSessionError::InsufficientMaxLength { n_out, max_tokens });
241 }
242 // SAFETY: we checked that n_out <= max_tokens and llama.cpp promises that n_out tokens will be written
243 unsafe {
244 tokens.set_len(n_out);
245 }
246 Ok(tokens)
247 } else {
248 Err(LoadSessionError::FailedToLoad)
249 }
250 }
251
252 /// Save the full state to a file.
253 ///
254 /// This is the non-deprecated replacement for [`save_session_file`](Self::save_session_file).
255 ///
256 /// # Parameters
257 ///
258 /// * `path_session` - The file to save to.
259 /// * `tokens` - The tokens to associate the state with. This should be a prefix of a sequence
260 /// of tokens that the context has processed, so that the relevant KV caches are already filled.
261 ///
262 /// # Errors
263 ///
264 /// Fails if the path is not a valid utf8, is not a valid c string, or llama.cpp fails to save
265 /// the state file.
266 pub fn state_save_file(
267 &self,
268 path_session: impl AsRef<Path>,
269 tokens: &[LlamaToken],
270 ) -> Result<(), SaveSessionError> {
271 let path = path_session.as_ref();
272 let path = path
273 .to_str()
274 .ok_or_else(|| SaveSessionError::PathToStrError(path.to_path_buf()))?;
275
276 let cstr = CString::new(path)?;
277
278 if unsafe {
279 ik_llama_cpp_sys::llama_state_save_file(
280 self.context.as_ptr(),
281 cstr.as_ptr(),
282 tokens.as_ptr().cast::<ik_llama_cpp_sys::llama_token>(),
283 tokens.len(),
284 )
285 } {
286 Ok(())
287 } else {
288 Err(SaveSessionError::FailedToSave)
289 }
290 }
291
292 /// Load a state file into the current context.
293 ///
294 /// This is the non-deprecated replacement for [`load_session_file`](Self::load_session_file).
295 ///
296 /// You still need to pass the returned tokens to the context for inference to work. What this
297 /// function buys you is that the KV caches are already filled with the relevant data.
298 ///
299 /// # Parameters
300 ///
301 /// * `path_session` - The file to load from. It must be a state file from a compatible context,
302 /// otherwise the function will error.
303 /// * `max_tokens` - The maximum token length of the loaded state. If the state was saved with a
304 /// longer length, the function will error.
305 ///
306 /// # Errors
307 ///
308 /// Fails if the path is not a valid utf8, is not a valid c string, or llama.cpp fails to load
309 /// the state file.
310 pub fn state_load_file(
311 &mut self,
312 path_session: impl AsRef<Path>,
313 max_tokens: usize,
314 ) -> Result<Vec<LlamaToken>, LoadSessionError> {
315 let path = path_session.as_ref();
316 let path = path
317 .to_str()
318 .ok_or(LoadSessionError::PathToStrError(path.to_path_buf()))?;
319
320 let cstr = CString::new(path)?;
321 let mut tokens: Vec<LlamaToken> = Vec::with_capacity(max_tokens);
322 let mut n_out = 0;
323
324 // SAFETY: cast is valid as LlamaToken is repr(transparent)
325 let tokens_out = tokens.as_mut_ptr().cast::<ik_llama_cpp_sys::llama_token>();
326
327 let success = unsafe {
328 ik_llama_cpp_sys::llama_state_load_file(
329 self.context.as_ptr(),
330 cstr.as_ptr(),
331 tokens_out,
332 max_tokens,
333 &mut n_out,
334 )
335 };
336 if success {
337 if n_out > max_tokens {
338 return Err(LoadSessionError::InsufficientMaxLength { n_out, max_tokens });
339 }
340 // SAFETY: we checked that n_out <= max_tokens and llama.cpp promises that n_out tokens will be written
341 unsafe {
342 tokens.set_len(n_out);
343 }
344 Ok(tokens)
345 } else {
346 Err(LoadSessionError::FailedToLoad)
347 }
348 }
349
350 /// Save state for a single sequence to a file.
351 ///
352 /// This enables saving state for individual sequences, which is useful for multi-sequence
353 /// inference scenarios.
354 ///
355 /// # Parameters
356 ///
357 /// * `filepath` - The file to save to.
358 /// * `seq_id` - The sequence ID whose state to save.
359 /// * `tokens` - The tokens to associate with the saved state.
360 ///
361 /// # Errors
362 ///
363 /// Fails if the path is not a valid utf8, is not a valid c string, or llama.cpp fails to save
364 /// the sequence state file.
365 ///
366 /// # Returns
367 ///
368 /// The number of bytes written on success.
369 pub fn state_seq_save_file(
370 &self,
371 filepath: impl AsRef<Path>,
372 seq_id: i32,
373 tokens: &[LlamaToken],
374 ) -> Result<usize, SaveSeqStateError> {
375 let path = filepath.as_ref();
376 let path = path
377 .to_str()
378 .ok_or_else(|| SaveSeqStateError::PathToStrError(path.to_path_buf()))?;
379
380 let cstr = CString::new(path)?;
381
382 let bytes_written = unsafe {
383 ik_llama_cpp_sys::llama_state_seq_save_file(
384 self.context.as_ptr(),
385 cstr.as_ptr(),
386 seq_id,
387 tokens.as_ptr().cast::<ik_llama_cpp_sys::llama_token>(),
388 tokens.len(),
389 )
390 };
391
392 if bytes_written == 0 {
393 Err(SaveSeqStateError::FailedToSave)
394 } else {
395 Ok(bytes_written)
396 }
397 }
398
399 /// Load state for a single sequence from a file.
400 ///
401 /// This enables loading state for individual sequences, which is useful for multi-sequence
402 /// inference scenarios.
403 ///
404 /// # Parameters
405 ///
406 /// * `filepath` - The file to load from.
407 /// * `dest_seq_id` - The destination sequence ID to load the state into.
408 /// * `max_tokens` - The maximum number of tokens to read.
409 ///
410 /// # Errors
411 ///
412 /// Fails if the path is not a valid utf8, is not a valid c string, or llama.cpp fails to load
413 /// the sequence state file.
414 ///
415 /// # Returns
416 ///
417 /// A tuple of `(tokens, bytes_read)` on success.
418 pub fn state_seq_load_file(
419 &mut self,
420 filepath: impl AsRef<Path>,
421 dest_seq_id: i32,
422 max_tokens: usize,
423 ) -> Result<(Vec<LlamaToken>, usize), LoadSeqStateError> {
424 let path = filepath.as_ref();
425 let path = path
426 .to_str()
427 .ok_or(LoadSeqStateError::PathToStrError(path.to_path_buf()))?;
428
429 let cstr = CString::new(path)?;
430 let mut tokens: Vec<LlamaToken> = Vec::with_capacity(max_tokens);
431 let mut n_out = 0;
432
433 // SAFETY: cast is valid as LlamaToken is repr(transparent)
434 let tokens_out = tokens.as_mut_ptr().cast::<ik_llama_cpp_sys::llama_token>();
435
436 let bytes_read = unsafe {
437 ik_llama_cpp_sys::llama_state_seq_load_file(
438 self.context.as_ptr(),
439 cstr.as_ptr(),
440 dest_seq_id,
441 tokens_out,
442 max_tokens,
443 &mut n_out,
444 )
445 };
446
447 if bytes_read == 0 {
448 return Err(LoadSeqStateError::FailedToLoad);
449 }
450
451 if n_out > max_tokens {
452 return Err(LoadSeqStateError::InsufficientMaxLength { n_out, max_tokens });
453 }
454
455 // SAFETY: we checked that n_out <= max_tokens and llama.cpp promises that n_out tokens will be written
456 unsafe {
457 tokens.set_len(n_out);
458 }
459
460 Ok((tokens, bytes_read))
461 }
462
463 /// Returns the maximum size in bytes of the state (rng, logits, embedding
464 /// and `kv_cache`) - will often be smaller after compacting tokens
465 #[must_use]
466 pub fn get_state_size(&self) -> usize {
467 unsafe { ik_llama_cpp_sys::llama_get_state_size(self.context.as_ptr()) }
468 }
469
470 /// Copies the state to the specified destination address.
471 ///
472 /// Returns the number of bytes copied
473 ///
474 /// # Safety
475 ///
476 /// Destination needs to have allocated enough memory.
477 pub unsafe fn copy_state_data(&self, dest: *mut u8) -> usize {
478 unsafe { ik_llama_cpp_sys::llama_copy_state_data(self.context.as_ptr(), dest) }
479 }
480
481 /// Restore context state from a buffer previously produced by
482 /// [`copy_state_data`](Self::copy_state_data) (or `llama_state_get_data`) for
483 /// a *compatible* context. Returns the number of bytes read.
484 ///
485 /// The buffer length is forwarded to ik's **sized** reader
486 /// (`llama_state_set_data`), so each field read is bounds-checked against
487 /// `src.len()` — a too-short buffer is rejected C-side instead of over-reading
488 /// past the slice (as the deprecated no-size `llama_set_state_data` would).
489 ///
490 /// # Safety
491 ///
492 /// `src` must be a valid serialized state blob for a context created with the
493 /// same model and compatible parameters. A malformed or mismatched blob can
494 /// make the C++ deserializer throw, which aborts the process across the FFI
495 /// boundary; only the out-of-bounds *read* is prevented here.
496 pub unsafe fn set_state_data(&mut self, src: &[u8]) -> usize {
497 unsafe {
498 ik_llama_cpp_sys::llama_state_set_data(self.context.as_ptr(), src.as_ptr(), src.len())
499 }
500 }
501
502 /// Get the size of the state for a single sequence with optional flags.
503 ///
504 /// This is the extended version that supports flags for partial state operations.
505 ///
506 /// # Parameters
507 ///
508 /// * `seq_id` - The sequence ID to get the state size for.
509 /// * `flags` - Optional flags (e.g., [`LlamaStateSeqFlags::PARTIAL_ONLY`]).
510 ///
511 /// # Returns
512 ///
513 /// The size in bytes needed to store the sequence state.
514 #[must_use]
515 pub fn state_seq_get_size_ext(&self, seq_id: i32, flags: LlamaStateSeqFlags) -> usize {
516 unsafe {
517 ik_llama_cpp_sys::llama_state_seq_get_size(self.context.as_ptr(), seq_id, flags.0)
518 }
519 }
520
521 /// Copy the state of a single sequence into the specified buffer with optional flags.
522 ///
523 /// This is the extended version that supports flags for partial state operations.
524 ///
525 /// # Parameters
526 ///
527 /// * `dest` - Destination buffer to copy state into.
528 /// * `seq_id` - The sequence ID to get the state for.
529 /// * `flags` - Optional flags (e.g., [`LlamaStateSeqFlags::PARTIAL_ONLY`]).
530 ///
531 /// # Safety
532 ///
533 /// Destination needs to have allocated enough memory.
534 ///
535 /// # Returns
536 ///
537 /// The number of bytes copied.
538 pub unsafe fn state_seq_get_data_ext(
539 &self,
540 dest: *mut u8,
541 seq_id: i32,
542 flags: LlamaStateSeqFlags,
543 ) -> usize {
544 unsafe {
545 ik_llama_cpp_sys::llama_state_seq_get_data(
546 self.context.as_ptr(),
547 dest,
548 usize::MAX,
549 seq_id,
550 flags.0,
551 )
552 }
553 }
554
555 /// Set the state for a single sequence from the specified buffer with optional flags.
556 ///
557 /// This is the extended version that supports flags for partial state operations.
558 /// Useful for restoring only the recurrent/partial state without affecting the KV cache.
559 ///
560 /// # Parameters
561 ///
562 /// * `src` - Source buffer containing the state data.
563 /// * `dest_seq_id` - The destination sequence ID to load the state into.
564 /// * `flags` - Optional flags (e.g., [`LlamaStateSeqFlags::PARTIAL_ONLY`]).
565 ///
566 /// # Safety
567 ///
568 /// The source buffer must contain valid state data.
569 ///
570 /// # Returns
571 ///
572 /// `true` on success (the whole `src` buffer was consumed). ik returns
573 /// `SIZE_MAX` when state IO is unsupported and `0` on other failures; both
574 /// are reported as `false` (only `n == src.len()` counts as success).
575 pub unsafe fn state_seq_set_data_ext(
576 &mut self,
577 src: &[u8],
578 dest_seq_id: i32,
579 flags: LlamaStateSeqFlags,
580 ) -> bool {
581 let n = unsafe {
582 ik_llama_cpp_sys::llama_state_seq_set_data(
583 self.context.as_ptr(),
584 src.as_ptr(),
585 src.len(),
586 dest_seq_id,
587 flags.0,
588 )
589 };
590 n == src.len()
591 }
592
593 /// Serialize sequence `seq_id`'s state into an opaque [`SeqState`].
594 ///
595 /// Enables save/restore of context state at arbitrary points in a
596 /// sequence. This is particularly useful on architectures where
597 /// `clear_kv_cache_seq` cannot roll back partial state (Mamba, RWKV,
598 /// Gated Delta Networks, and other recurrent / hybrid-recurrent
599 /// models): pair with [`LlamaStateSeqFlags::PARTIAL_ONLY`] to save
600 /// just the running recurrent and SWA state, then restore it via
601 /// [`Self::state_seq_set`] to effectively "rewind" the sequence.
602 ///
603 /// The returned [`SeqState`] is opaque — its bytes cannot be
604 /// inspected or forged from safe code, so [`Self::state_seq_set`]
605 /// only ever sees data produced by this method.
606 ///
607 /// Wraps `llama_state_seq_get_data`.
608 ///
609 /// # Errors
610 ///
611 /// Returns [`StateSeqError::SizeMismatch`] if llama.cpp writes a
612 /// different number of bytes than the reported state size.
613 pub fn state_seq_get(
614 &self,
615 seq_id: i32,
616 flags: LlamaStateSeqFlags,
617 ) -> Result<SeqState, StateSeqError> {
618 let size = unsafe {
619 ik_llama_cpp_sys::llama_state_seq_get_size(self.context.as_ptr(), seq_id, flags.0)
620 };
621 let mut bytes = vec![0u8; size];
622 let n = unsafe {
623 ik_llama_cpp_sys::llama_state_seq_get_data(
624 self.context.as_ptr(),
625 bytes.as_mut_ptr(),
626 size,
627 seq_id,
628 flags.0,
629 )
630 };
631 if n != size {
632 return Err(StateSeqError::SizeMismatch {
633 expected: size,
634 actual: n,
635 });
636 }
637 Ok(SeqState { bytes, flags })
638 }
639
640 /// Restore sequence state previously captured by [`Self::state_seq_get`]
641 /// into `seq_id`.
642 ///
643 /// Cross-sequence restore (`seq_id` different from the sequence the
644 /// state was captured from) is supported — llama.cpp treats the
645 /// destination sequence id independently of the source.
646 ///
647 /// Wraps `llama_state_seq_set_data`.
648 ///
649 /// # Errors
650 ///
651 /// Returns [`StateSeqError::SizeMismatch`] if llama.cpp reads a
652 /// different number of bytes than the state buffer contains — this
653 /// covers shape mismatches (different `n_ctx`, `n_layer`, quantization,
654 /// etc.) that llama.cpp's own deserializer detects and aborts on.
655 pub fn state_seq_set(&mut self, state: &SeqState, seq_id: i32) -> Result<(), StateSeqError> {
656 let n = unsafe {
657 ik_llama_cpp_sys::llama_state_seq_set_data(
658 self.context.as_ptr(),
659 state.bytes.as_ptr(),
660 state.bytes.len(),
661 seq_id,
662 state.flags.0,
663 )
664 };
665 if n != state.bytes.len() {
666 return Err(StateSeqError::SizeMismatch {
667 expected: state.bytes.len(),
668 actual: n,
669 });
670 }
671 Ok(())
672 }
673}
674
675/// Opaque, immutable snapshot of a single sequence's state.
676///
677/// Produced by [`LlamaContext::state_seq_get`] and consumed by
678/// [`LlamaContext::state_seq_set`]. Bytes cannot be constructed, forged,
679/// or mutated from safe code — the only way to obtain a `SeqState` is
680/// via a get call, which guarantees the payload came from llama.cpp
681/// itself. Combined with llama.cpp's own shape validation on the
682/// deserialize path, this closes the "arbitrary bytes into C parser"
683/// unsoundness that motivates the unsafe raw setters.
684///
685/// The state carries the flag set it was captured with; restore uses
686/// those same flags automatically so the byte layout always matches.
687#[derive(Clone)]
688pub struct SeqState {
689 bytes: Vec<u8>,
690 flags: LlamaStateSeqFlags,
691}
692
693impl SeqState {
694 /// The flag set that was used to capture this state.
695 #[must_use]
696 pub fn flags(&self) -> LlamaStateSeqFlags {
697 self.flags
698 }
699
700 /// Size in bytes of the serialized state.
701 #[must_use]
702 pub fn byte_len(&self) -> usize {
703 self.bytes.len()
704 }
705}
706
707impl Debug for SeqState {
708 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
709 f.debug_struct("SeqState")
710 .field("byte_len", &self.bytes.len())
711 .field("flags", &self.flags)
712 .finish()
713 }
714}