use skippy_ffi::{
FEATURE_DEVICE_EVENTS, FEATURE_KV_EVENTS, FEATURE_MODEL_LOAD_EVENTS_V2,
FEATURE_RUNTIME_EVENT_REPORTER, FEATURE_RUNTIME_EVENTS,
};
pub(super) const BACKEND_CATEGORY: u8 = 1 << 0;
pub(super) const MODEL_CATEGORY: u8 = 1 << 1;
const MEMORY_CATEGORY: u8 = 1 << 2;
const KV_CACHE_CATEGORY: u8 = 1 << 3;
const TOKENIZER_CATEGORY: u8 = 1 << 4;
pub(super) const MODEL_FALLBACK_NOTE: u8 = 1 << 5;
pub(super) const ALL_PRESENTATION_CATEGORIES: u8 =
BACKEND_CATEGORY | MODEL_CATEGORY | MEMORY_CATEGORY | KV_CACHE_CATEGORY | TOKENIZER_CATEGORY;
pub(super) const ALL_FORWARDING_CATEGORIES: u8 = ALL_PRESENTATION_CATEGORIES | MODEL_FALLBACK_NOTE;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NativeLogParserMode {
Auto,
Enabled,
Disabled,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct NativeLogParserPolicy {
pub(super) forwarding_mask: u8,
}
impl NativeLogParserPolicy {
pub fn new(mode: NativeLogParserMode, capabilities: &crate::CapabilityReport) -> Self {
let forwarding_mask = match mode {
NativeLogParserMode::Enabled => ALL_FORWARDING_CATEGORIES,
NativeLogParserMode::Disabled => 0,
NativeLogParserMode::Auto => {
(ALL_PRESENTATION_CATEGORIES & !structured_coverage(capabilities))
| MODEL_FALLBACK_NOTE
}
};
Self { forwarding_mask }
}
pub fn forwards(self, category: &str) -> bool {
category_mask(category).is_some_and(|mask| self.forwarding_mask & mask != 0)
}
#[must_use]
pub fn forwards_model_fallback_note(self) -> bool {
self.forwarding_mask & MODEL_FALLBACK_NOTE != 0
}
}
fn structured_coverage(capabilities: &crate::CapabilityReport) -> u8 {
if !capabilities.family_confirmed(FEATURE_RUNTIME_EVENT_REPORTER) {
return 0;
}
let mut covered = 0;
if capabilities.family_confirmed(FEATURE_DEVICE_EVENTS) {
covered |= BACKEND_CATEGORY;
}
if capabilities.family_confirmed(FEATURE_KV_EVENTS) {
covered |= KV_CACHE_CATEGORY;
}
if capabilities.family_confirmed(FEATURE_MODEL_LOAD_EVENTS_V2) {
covered |= MEMORY_CATEGORY | TOKENIZER_CATEGORY;
if capabilities.family_confirmed(FEATURE_RUNTIME_EVENTS) {
covered |= MODEL_CATEGORY;
}
}
covered
}
pub(super) fn category_mask(category: &str) -> Option<u8> {
match category {
"backend" => Some(BACKEND_CATEGORY),
"model" => Some(MODEL_CATEGORY),
"memory" => Some(MEMORY_CATEGORY),
"kv_cache" => Some(KV_CACHE_CATEGORY),
"tokenizer" => Some(TOKENIZER_CATEGORY),
_ => None,
}
}