feat: splitting

This commit is contained in:
2026-09-26 01:15:12 -04:00
parent 220363d4d3
commit eabc98ad31
29 changed files with 4843 additions and 234 deletions
+48 -1
View File
@@ -16,7 +16,7 @@ use std::fs;
use std::path::Path;
use serde::de::{self, DeserializeOwned, Visitor};
use serde::{Deserializer, Serialize};
use serde::{Deserialize, Deserializer, Serialize};
use crate::error::{Error, Result};
@@ -61,6 +61,26 @@ pub fn write<T: Serialize>(path: &Path, value: &T) -> Result<()> {
fs::write(path, text).map_err(|e| Error::io(path, e))
}
/// Serializes a value to a YAML string.
///
/// Used where the caller needs to put something in front of the document, such
/// as the banner on a generated file.
///
/// # Arguments
///
/// * `value` - the value to serialize.
///
/// # Returns
///
/// The YAML text.
///
/// # Errors
///
/// Returns [`Error::Other`] if the value cannot be represented as YAML.
pub fn to_string<T: Serialize>(value: &T) -> Result<String> {
serde_yaml_ng::to_string(value).map_err(Error::other)
}
/// Deserializes a JSON file into any type.
///
/// Used only for importing legacy banks and for reading emitted schemas back in
@@ -202,6 +222,33 @@ where
d.deserialize_any(V)
}
/// Deserializes an optional scalar as a string, quoted or not.
///
/// The [`flexible_string`] of a field that may be absent, which is what a
/// fragment's `schema_version` is: one file in a course declares it and the
/// rest inherit.
///
/// # Arguments
///
/// * `d` - the deserializer.
///
/// # Returns
///
/// The value as a string, or `None`.
///
/// # Errors
///
/// Returns a deserialization error for non-scalar input.
pub fn flexible_string_opt<'de, D>(d: D) -> std::result::Result<Option<String>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(serde::Deserialize)]
struct Wrapper(#[serde(deserialize_with = "flexible_string")] String);
Ok(Option::<Wrapper>::deserialize(d)?.map(|w| w.0))
}
#[cfg(test)]
mod tests {
use super::*;