Before going crazy

This commit is contained in:
2026-01-28 18:05:50 +01:00
parent 2be15d11f4
commit d106711708
11 changed files with 459 additions and 299 deletions

View File

@@ -7,6 +7,15 @@ use serde::{Deserialize, Serialize};
use crate::project::{Bank, Project};
const VERSION: u8 = 1;
pub const EXTENSION: &str = "cagire";
pub fn ensure_extension(path: &Path) -> PathBuf {
if path.extension().map(|e| e == EXTENSION).unwrap_or(false) {
path.to_path_buf()
} else {
path.with_extension(EXTENSION)
}
}
#[derive(Serialize, Deserialize)]
struct ProjectFile {
@@ -74,11 +83,12 @@ impl From<serde_json::Error> for FileError {
}
}
pub fn save(project: &Project, path: &Path) -> Result<(), FileError> {
pub fn save(project: &Project, path: &Path) -> Result<PathBuf, FileError> {
let path = ensure_extension(path);
let file = ProjectFile::from(project);
let json = serde_json::to_string_pretty(&file)?;
fs::write(path, json)?;
Ok(())
fs::write(&path, json)?;
Ok(path)
}
pub fn load(path: &Path) -> Result<Project, FileError> {

View File

@@ -216,6 +216,12 @@ pub struct Step {
pub source: Option<usize>,
}
impl Step {
pub fn is_default(&self) -> bool {
self.active && self.script.is_empty() && self.source.is_none()
}
}
impl Default for Step {
fn default() -> Self {
Self {
@@ -227,20 +233,141 @@ impl Default for Step {
}
}
#[derive(Clone, Serialize, Deserialize)]
#[derive(Clone)]
pub struct Pattern {
pub steps: Vec<Step>,
pub length: usize,
#[serde(default)]
pub speed: PatternSpeed,
#[serde(default)]
pub name: Option<String>,
#[serde(default)]
pub quantization: LaunchQuantization,
#[serde(default)]
pub sync_mode: SyncMode,
}
#[derive(Serialize, Deserialize)]
struct SparseStep {
i: usize,
#[serde(default = "default_active", skip_serializing_if = "is_true")]
active: bool,
#[serde(default, skip_serializing_if = "String::is_empty")]
script: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
source: Option<usize>,
}
fn default_active() -> bool {
true
}
fn is_true(v: &bool) -> bool {
*v
}
#[derive(Serialize, Deserialize)]
struct SparsePattern {
steps: Vec<SparseStep>,
length: usize,
#[serde(default)]
speed: PatternSpeed,
#[serde(default, skip_serializing_if = "Option::is_none")]
name: Option<String>,
#[serde(default, skip_serializing_if = "is_default_quantization")]
quantization: LaunchQuantization,
#[serde(default, skip_serializing_if = "is_default_sync_mode")]
sync_mode: SyncMode,
}
fn is_default_quantization(q: &LaunchQuantization) -> bool {
*q == LaunchQuantization::default()
}
fn is_default_sync_mode(s: &SyncMode) -> bool {
*s == SyncMode::default()
}
#[derive(Deserialize)]
struct LegacyPattern {
steps: Vec<Step>,
length: usize,
#[serde(default)]
speed: PatternSpeed,
#[serde(default)]
name: Option<String>,
#[serde(default)]
quantization: LaunchQuantization,
#[serde(default)]
sync_mode: SyncMode,
}
impl Serialize for Pattern {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let sparse_steps: Vec<SparseStep> = self
.steps
.iter()
.enumerate()
.filter(|(_, step)| !step.is_default())
.map(|(i, step)| SparseStep {
i,
active: step.active,
script: step.script.clone(),
source: step.source,
})
.collect();
let sparse = SparsePattern {
steps: sparse_steps,
length: self.length,
speed: self.speed,
name: self.name.clone(),
quantization: self.quantization,
sync_mode: self.sync_mode,
};
sparse.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Pattern {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Deserialize)]
#[serde(untagged)]
enum PatternFormat {
Sparse(SparsePattern),
Legacy(LegacyPattern),
}
match PatternFormat::deserialize(deserializer)? {
PatternFormat::Sparse(sparse) => {
let mut steps: Vec<Step> = (0..MAX_STEPS).map(|_| Step::default()).collect();
for ss in sparse.steps {
if ss.i < MAX_STEPS {
steps[ss.i] = Step {
active: ss.active,
script: ss.script,
command: None,
source: ss.source,
};
}
}
Ok(Pattern {
steps,
length: sparse.length,
speed: sparse.speed,
name: sparse.name,
quantization: sparse.quantization,
sync_mode: sparse.sync_mode,
})
}
PatternFormat::Legacy(legacy) => Ok(Pattern {
steps: legacy.steps,
length: legacy.length,
speed: legacy.speed,
name: legacy.name,
quantization: legacy.quantization,
sync_mode: legacy.sync_mode,
}),
}
}
}
impl Default for Pattern {
fn default() -> Self {
Self {