Skip to main content

oxihuman_morph/
streaming_morph.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Streaming morph target loader stub.
6
7/// State of a streaming morph load operation.
8#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum StreamState {
10    Idle,
11    Loading,
12    Ready,
13    Error,
14}
15
16/// A streaming morph target entry in the queue.
17#[derive(Debug, Clone)]
18pub struct StreamEntry {
19    pub name: String,
20    pub priority: u8,
21    pub state: StreamState,
22}
23
24/// Streaming morph target loader.
25#[derive(Debug, Clone)]
26pub struct StreamingMorph {
27    pub queue: Vec<StreamEntry>,
28    pub max_concurrent: usize,
29    pub enabled: bool,
30}
31
32impl StreamingMorph {
33    pub fn new(max_concurrent: usize) -> Self {
34        StreamingMorph {
35            queue: Vec::new(),
36            max_concurrent,
37            enabled: true,
38        }
39    }
40}
41
42/// Create a new streaming morph loader.
43pub fn new_streaming_morph(max_concurrent: usize) -> StreamingMorph {
44    StreamingMorph::new(max_concurrent)
45}
46
47/// Enqueue a morph target for streaming.
48pub fn sm_enqueue(loader: &mut StreamingMorph, name: impl Into<String>, priority: u8) {
49    loader.queue.push(StreamEntry {
50        name: name.into(),
51        priority,
52        state: StreamState::Idle,
53    });
54}
55
56/// Tick the loader: marks pending entries as Loading (stub).
57pub fn sm_tick(loader: &mut StreamingMorph) {
58    /* Stub: advance up to max_concurrent entries from Idle to Loading */
59    let mut loading_count = loader
60        .queue
61        .iter()
62        .filter(|e| e.state == StreamState::Loading)
63        .count();
64    for entry in &mut loader.queue {
65        if loading_count >= loader.max_concurrent {
66            break;
67        }
68        if entry.state == StreamState::Idle {
69            entry.state = StreamState::Loading;
70            loading_count += 1;
71        }
72    }
73}
74
75/// Return queue length.
76pub fn sm_queue_len(loader: &StreamingMorph) -> usize {
77    loader.queue.len()
78}
79
80/// Enable or disable the loader.
81pub fn sm_set_enabled(loader: &mut StreamingMorph, enabled: bool) {
82    loader.enabled = enabled;
83}
84
85/// Serialize to JSON-like string.
86pub fn sm_to_json(loader: &StreamingMorph) -> String {
87    format!(
88        r#"{{"queue_len":{},"max_concurrent":{},"enabled":{}}}"#,
89        loader.queue.len(),
90        loader.max_concurrent,
91        loader.enabled
92    )
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[test]
100    fn test_new_empty_queue() {
101        let l = new_streaming_morph(4);
102        assert_eq!(sm_queue_len(&l), 0 /* queue must be empty initially */,);
103    }
104
105    #[test]
106    fn test_enqueue() {
107        let mut l = new_streaming_morph(4);
108        sm_enqueue(&mut l, "brow_raise", 10);
109        assert_eq!(sm_queue_len(&l), 1 /* one entry after enqueue */,);
110    }
111
112    #[test]
113    fn test_tick_sets_loading() {
114        let mut l = new_streaming_morph(2);
115        sm_enqueue(&mut l, "a", 1);
116        sm_enqueue(&mut l, "b", 2);
117        sm_enqueue(&mut l, "c", 3);
118        sm_tick(&mut l);
119        let loading = l
120            .queue
121            .iter()
122            .filter(|e| e.state == StreamState::Loading)
123            .count();
124        assert_eq!(
125            loading,
126            2, /* only max_concurrent entries should be loading */
127        );
128    }
129
130    #[test]
131    fn test_tick_respects_max() {
132        let mut l = new_streaming_morph(1);
133        sm_enqueue(&mut l, "x", 5);
134        sm_enqueue(&mut l, "y", 3);
135        sm_tick(&mut l);
136        let loading = l
137            .queue
138            .iter()
139            .filter(|e| e.state == StreamState::Loading)
140            .count();
141        assert_eq!(loading, 1 /* only 1 entry loading at a time */,);
142    }
143
144    #[test]
145    fn test_initial_state_idle() {
146        let mut l = new_streaming_morph(2);
147        sm_enqueue(&mut l, "z", 0);
148        assert_eq!(
149            l.queue[0].state,
150            StreamState::Idle, /* must start as Idle */
151        );
152    }
153
154    #[test]
155    fn test_set_enabled() {
156        let mut l = new_streaming_morph(2);
157        sm_set_enabled(&mut l, false);
158        assert!(!l.enabled /* must be disabled */,);
159    }
160
161    #[test]
162    fn test_to_json_contains_queue_len() {
163        let l = new_streaming_morph(4);
164        let j = sm_to_json(&l);
165        assert!(j.contains("\"queue_len\""), /* json must contain queue_len */);
166    }
167
168    #[test]
169    fn test_priority_stored() {
170        let mut l = new_streaming_morph(4);
171        sm_enqueue(&mut l, "hi", 255);
172        assert_eq!(l.queue[0].priority, 255 /* priority must be stored */,);
173    }
174
175    #[test]
176    fn test_max_concurrent_stored() {
177        let l = new_streaming_morph(8);
178        assert_eq!(l.max_concurrent, 8 /* max_concurrent must match */,);
179    }
180
181    #[test]
182    fn test_enabled_default() {
183        let l = new_streaming_morph(2);
184        assert!(l.enabled /* must be enabled by default */,);
185    }
186}