#![doc = "../README.md"]
use std::{borrow::Cow, collections::HashMap, path::PathBuf};
use bliplib::compiler::Expression;
use derive_new::new;
use serde::{Deserialize, Serialize};
use serde_with::{DisplayFromStr, serde_as};
#[cfg(feature = "example-skip-defaults")]
fn is_default<T: Default + PartialEq>(t: &T) -> bool {
t == &T::default()
}
#[derive(new, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Song<'a> {
#[serde(default)]
#[cfg_attr(
feature = "example-skip-defaults",
serde(skip_serializing_if = "is_default")
)]
global_variables: Globals,
#[new(into_iter = "(Cow<'a, str>, Channel<'a>)")]
channels: HashMap<Cow<'a, str>, Channel<'a>>,
}
#[derive(new, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Globals {
#[new(into)]
absolute_length: char,
#[new(into)]
note_index: char,
}
impl Default for Globals {
fn default() -> Self {
Self::new('L', 'n')
}
}
#[serde_as]
#[derive(new, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Channel<'a> {
input: PathOrString<'a>,
#[new(into_iter = "Cow<'a, str>")]
notes: Vec<Cow<'a, str>>,
#[serde_as(as = "DisplayFromStr")]
instrument: Expression,
#[new(into_iter = "(char, f64)")]
#[serde(default)]
#[cfg_attr(
feature = "example-skip-defaults",
serde(skip_serializing_if = "is_default")
)]
variables: HashMap<char, f64>,
#[new(into_iter = "(char, Cow<'a, str>)")]
#[serde(default)]
#[cfg_attr(
feature = "example-skip-defaults",
serde(skip_serializing_if = "is_default")
)]
macros: HashMap<char, Cow<'a, str>>,
#[new(into_iter = "(Cow<'a, str>, VariableChange)")]
#[serde(default = "default_slope")]
slopes: HashMap<Cow<'a, str>, VariableChange>,
}
fn default_slope<'a>() -> HashMap<Cow<'a, str>, VariableChange> {
[(
"L".into(),
VariableChange::new(
'L',
"2^(2-log(2, l))*(60/T)"
.parse()
.expect("oops, my default length expression doesn't work"),
),
)]
.into()
}
#[serde_as]
#[derive(new, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct VariableChange {
target: char,
#[serde_as(as = "DisplayFromStr")]
change: Expression,
}
impl From<bliplib::compiler::VariableChange> for VariableChange {
fn from(value: bliplib::compiler::VariableChange) -> Self {
Self {
target: value.0,
change: value.1,
}
}
}
impl From<VariableChange> for bliplib::compiler::VariableChange {
fn from(value: VariableChange) -> Self {
Self(value.target, value.change)
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[serde(deny_unknown_fields)]
pub enum PathOrString<'a> {
Path(PathBuf),
String(Cow<'a, str>),
}