#![cfg(feature = "method_lib_serde")]
use std::collections::HashMap;
use itertools::Itertools;
use serde_crate::{Deserialize, Serialize};
use crate::{
method::{
class::{Class, FullClass},
generate_title,
},
Stage,
};
use super::{CompactMethod, LibraryMap, MethodLib};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(crate = "serde_crate")]
pub struct MethodLibSerde {
groups: Vec<MethodGroup>,
}
impl From<&MethodLib> for MethodLibSerde {
fn from(lib: &MethodLib) -> Self {
let mut groups: HashMap<(Stage, FullClass), Vec<&CompactMethod>> = HashMap::new();
for (stage, methods) in &lib.method_map {
for method in methods.values() {
groups
.entry((*stage, method.full_class))
.or_default()
.push(method);
}
}
Self {
groups: groups
.into_iter()
.map(|((stage, full_class), compact_methods)| {
let methods = compact_methods
.into_iter()
.map(|comp_method| CompactMethodSerde {
title: comp_method.omit_class.then(|| comp_method.title()),
name: comp_method.name.to_owned(),
place_notation: comp_method.place_notation.to_owned(),
})
.collect_vec();
MethodGroup {
stage: stage.num_bells_u8(),
is_jump: full_class.is_jump(),
is_little: full_class.is_little(),
is_differential: full_class.is_differential(),
class_id: to_class_id(full_class.class()),
methods,
}
})
.collect_vec(),
}
}
}
impl From<MethodLibSerde> for MethodLib {
fn from(m: MethodLibSerde) -> MethodLib {
let mut unpacked_method_map: LibraryMap = HashMap::with_capacity(25);
for group in m.groups {
let stage = Stage::new(group.stage);
let full_class = FullClass::new(
group.is_jump,
group.is_little,
group.is_differential,
from_class_id(group.class_id).expect("Unexpected type ID found"),
);
let method_map = unpacked_method_map.entry(stage).or_default();
for m in group.methods {
let CompactMethodSerde {
title,
name,
place_notation,
} = m;
let omit_class = title.is_some();
method_map.insert(
title
.unwrap_or_else(|| generate_title(&name, full_class, false, stage))
.to_lowercase(),
CompactMethod {
name,
full_class,
omit_class,
place_notation,
stage,
},
);
}
}
MethodLib {
method_map: unpacked_method_map,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(crate = "serde_crate")]
struct MethodGroup {
#[serde(rename = "s")]
stage: u8,
#[serde(default, skip_serializing_if = "is_false", rename = "j")]
is_jump: bool,
#[serde(default, skip_serializing_if = "is_false", rename = "l")]
is_little: bool,
#[serde(default, skip_serializing_if = "is_false", rename = "d")]
is_differential: bool,
#[serde(rename = "c")]
class_id: u8,
#[serde(rename = "m")]
methods: Vec<CompactMethodSerde>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(crate = "serde_crate")]
struct CompactMethodSerde {
#[serde(skip_serializing_if = "Option::is_none", rename = "t")]
title: Option<String>,
#[serde(rename = "n")]
name: String,
#[serde(rename = "p")]
place_notation: String,
}
fn is_false(b: &bool) -> bool {
!(*b)
}
fn to_class_id(class: Class) -> u8 {
match class {
Class::Principle => 0,
Class::Place => 1,
Class::Bob => 2,
Class::TrebleBob => 3,
Class::Delight => 4,
Class::Surprise => 5,
Class::TreblePlace => 6,
Class::Alliance => 7,
Class::Hybrid => 8,
}
}
fn from_class_id(v: u8) -> Option<Class> {
Some(match v {
0 => Class::Principle,
1 => Class::Place,
2 => Class::Bob,
3 => Class::TrebleBob,
4 => Class::Delight,
5 => Class::Surprise,
6 => Class::TreblePlace,
7 => Class::Alliance,
8 => Class::Hybrid,
_ => panic!("Invalid Class ID {}", v),
})
}