use alloc::string::{String, ToString};
use onerom_config::chip::ChipType;
#[derive(Debug, Clone)]
pub struct ChipTypeSpec {
raw: String,
resolved: ChipType,
}
impl ChipTypeSpec {
pub fn new(raw: String, resolved: ChipType) -> Self {
Self { raw, resolved }
}
pub fn resolved(&self) -> ChipType {
self.resolved
}
pub fn resolved_ref(&self) -> &ChipType {
&self.resolved
}
pub fn raw(&self) -> &str {
&self.raw
}
}
impl From<ChipType> for ChipTypeSpec {
fn from(resolved: ChipType) -> Self {
Self {
raw: resolved.name().to_string(),
resolved,
}
}
}
impl serde::Serialize for ChipTypeSpec {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.raw)
}
}
impl<'de> serde::Deserialize<'de> for ChipTypeSpec {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let raw = String::deserialize(deserializer)?;
let resolved = match ChipType::try_from_str(&raw) {
Some(chip_type) => chip_type,
None => ChipType::deserialize(
serde::de::value::BorrowedStrDeserializer::<D::Error>::new(&raw),
)?,
};
Ok(Self { raw, resolved })
}
}
#[cfg(feature = "schemars")]
impl schemars::JsonSchema for ChipTypeSpec {
fn schema_name() -> alloc::borrow::Cow<'static, str> {
ChipType::schema_name()
}
fn schema_id() -> alloc::borrow::Cow<'static, str> {
ChipType::schema_id()
}
fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
ChipType::json_schema(generator)
}
fn inline_schema() -> bool {
ChipType::inline_schema()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deserialize_preserves_raw_spelling() {
let spec: ChipTypeSpec = serde_json::from_str("\"27SF512\"").unwrap();
assert_eq!(spec.raw(), "27SF512");
assert_eq!(spec.resolved(), ChipType::Chip27512);
}
#[test]
fn deserialize_canonical_spelling() {
let spec: ChipTypeSpec = serde_json::from_str("\"27512\"").unwrap();
assert_eq!(spec.raw(), "27512");
assert_eq!(spec.resolved(), ChipType::Chip27512);
}
#[test]
fn serialize_emits_raw_spelling() {
let spec = ChipTypeSpec::new("27LC512".to_string(), ChipType::Chip27512);
assert_eq!(serde_json::to_string(&spec).unwrap(), "\"27LC512\"");
}
#[test]
fn round_trip_is_faithful() {
let json = "\"27C512\"";
let spec: ChipTypeSpec = serde_json::from_str(json).unwrap();
assert_eq!(serde_json::to_string(&spec).unwrap(), json);
}
#[test]
fn deserialize_is_case_insensitive_and_round_trips() {
let spec: ChipTypeSpec = serde_json::from_str("\"27lc512\"").unwrap();
assert_eq!(spec.raw(), "27lc512");
assert_eq!(spec.resolved(), ChipType::Chip27512);
let json = serde_json::to_string(&spec).unwrap();
assert_eq!(json, "\"27lc512\"");
let again: ChipTypeSpec = serde_json::from_str(&json).unwrap();
assert_eq!(again.raw(), "27lc512");
assert_eq!(again.resolved(), ChipType::Chip27512);
}
#[test]
fn debug_name_still_resolves() {
let spec: ChipTypeSpec = serde_json::from_str("\"Chip27512\"").unwrap();
assert_eq!(spec.resolved(), ChipType::Chip27512);
}
#[test]
fn unrecognised_spelling_is_error() {
assert!(serde_json::from_str::<ChipTypeSpec>("\"not-a-rom\"").is_err());
}
#[test]
fn from_chip_type_uses_canonical_name() {
let spec = ChipTypeSpec::from(ChipType::Chip27512);
assert_eq!(spec.raw(), "27512");
assert_eq!(spec.resolved(), ChipType::Chip27512);
}
}