// Oak Video Editor - Non-Linear Video Editor
// Copyright (C) 2026 Oak Team
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//! `ProjectLoadBaseTask` / `ProjectLoadTask`, mirroring
//! `src/task/src/project/load/load.h`.
//!
//! Loads an `.oakproj` file into a new `oak_node::project::Project`. The
//! base task holds the filename and produces the project on
//! `take_project()`; `ProjectLoadTask` is the concrete (OTIO-less) loader.
//! The project itself is loaded through the direct Rust serializer
//! (`oak_node::serializer::load` — single-lib unification; the old oaknode
//! serializer C ABI with its per-code result mapping is gone, so the
//! version/result-code ladder collapses into the error message the XML
//! path used).
//!
//! CPP-PARITY: src/task/src/project/load/load.h
use std::sync::{Arc, Mutex};
use oak_node::project::Project;
use crate::error::{Error, Result};
use crate::task::{Task, TaskBehavior};
/// The base project-load task: owns a source filename and yields a loaded
/// project via [`ProjectLoadBaseTask::take_project`].
pub struct ProjectLoadBaseTask {
/// The shared task base.
pub base: Task,
/// Absolute project filename to load.
pub filename: String,
/// The loaded project, produced by the task and taken via `take_project`.
loaded_project: Option>>,
}
impl ProjectLoadBaseTask {
/// Create a base load task for the given filename.
pub fn new(base: Task, filename: String) -> ProjectLoadBaseTask {
ProjectLoadBaseTask {
base,
filename,
loaded_project: None,
}
}
/// Take ownership of the loaded project. Returns `Err(Error::State)` if
/// the task has not loaded a project yet.
pub fn take_project(&mut self) -> Result>> {
self.loaded_project.take().ok_or(Error::State)
}
/// Store the loaded project (called by `run`).
pub(crate) fn store_project(&mut self, project: Arc>) {
self.loaded_project = Some(project);
}
}
impl TaskBehavior for ProjectLoadBaseTask {
/// Load the project from `filename` via the direct oaknode serializer
/// (`oak_node::serializer::load`), storing the resulting project.
fn run(&mut self, task: &mut Task) -> Result<()> {
let xml = match std::fs::read_to_string(&self.filename) {
Ok(xml) => xml,
Err(e) => {
task.set_error(&format!(
"Failed to read file \"{}\" for reading.",
self.filename
));
let _ = e;
return Err(Error::Failed("Failed to load project".to_string()));
}
};
let project = match oak_node::serializer::load(&xml) {
Ok(project) => project,
Err(e) => {
task.set_error(&format!(
"Failed to read XML document. File may be corrupt. Error was: {e}"
));
return Err(Error::Failed("Failed to load project".to_string()));
}
};
{
let mut guard = project.lock().unwrap_or_else(|e| e.into_inner());
guard.set_filename(&self.filename);
}
self.store_project(project);
Ok(())
}
}
/// The concrete native project loader (no OTIO path).
pub struct ProjectLoadTask {
/// The shared task base.
pub base: ProjectLoadBaseTask,
}
impl TaskBehavior for ProjectLoadTask {
fn run(&mut self, task: &mut Task) -> Result<()> {
::run(&mut self.base, task)
}
}