(
&mut self,
start_line: usize,
frame: u32,
key_mode: AnimationKeyMode,
header: &str,
object_types: &HashMap<String, NodeType>,
)
| 229 | line, |
| 230 | object_types, |
| 231 | )?); |
| 232 | continue; |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | if let Some((k, v)) = split_key_value(line) |
| 237 | && k == "emit_signal" |
| 238 | { |
| 239 | actions.push(FrameAction::Event { |
| 240 | frame, |
| 241 | scope: AnimationEventScope::Global, |
| 242 | event: parse_emit_signal(v, line_no)?, |
| 243 | }); |
| 244 | continue; |
| 245 | } |
| 246 | |
| 247 | return Err(format!("line {}: invalid frame entry `{}`", line_no, line)); |
| 248 | } |
| 249 | |
| 250 | Err(format!("line {}: missing frame footer", start_line)) |
| 251 | } |
| 252 | |
| 253 | fn parse_object_block( |
| 254 | &mut self, |
| 255 | start_line: usize, |
| 256 | frame: u32, |
| 257 | key_mode: AnimationKeyMode, |
| 258 | header: &str, |
| 259 | object_types: &HashMap<String, NodeType>, |
| 260 | ) -> Result<Vec<FrameAction>, String> { |
| 261 | let object = header |
| 262 | .strip_prefix('@') |
| 263 | .and_then(|v| v.strip_suffix('{')) |
| 264 | .map(str::trim) |
| 265 | .filter(|s| !s.is_empty()) |
| 266 | .ok_or_else(|| format!("line {}: invalid object header", start_line))? |
| 267 | .to_string(); |
| 268 | |
| 269 | let node_type = object_types |
| 270 | .get(&object) |
| 271 | .ok_or_else(|| format!("line {}: unknown object `@{}`", start_line, object))?; |
| 272 | let node_type_name = node_type.as_str(); |
| 273 | let mut actions = Vec::new(); |
| 274 | while let Some((line_no, line)) = self.next_line() { |
| 275 | let line = strip_comment(line).trim(); |
| 276 | if line.is_empty() { |
| 277 | continue; |
| 278 | } |
| 279 | if line == "}" { |
| 280 | return Ok(actions); |
| 281 | } |
| 282 | |
| 283 | let Some((k, v)) = split_key_value(line) else { |
| 284 | return Err(format!( |
| 285 | "line {}: expected `key = value` inside object block", |
| 286 | line_no |
| 287 | )); |
| 288 | }; |
no test coverage detected