use std::collections::BTreeMap;
use crate::types::TypePath;
pub(crate) const DEFAULT_EXTERNAL_TYPES: &[(&str, &str)] = &[
("chrono::DateTime", "string"),
("chrono::NaiveDate", "string"),
("chrono::NaiveDateTime", "string"),
("chrono::NaiveTime", "string"),
("time::OffsetDateTime", "string"),
("time::PrimitiveDateTime", "string"),
("time::Date", "string"),
("time::Time", "string"),
("uuid::Uuid", "string"),
("url::Url", "string"),
("std::path::PathBuf", "string"),
("std::path::Path", "string"),
("std::ffi::OsString", "string"),
("std::ffi::OsStr", "string"),
("std::ffi::CString", "string"),
("std::ffi::CStr", "string"),
("std::net::IpAddr", "string"),
("std::net::Ipv4Addr", "string"),
("std::net::Ipv6Addr", "string"),
("serde_json::Value", "unknown"),
];
pub(crate) fn resolve(canonical: &TypePath, user_overrides: &BTreeMap<String, String>) -> Option<String> {
let key = canonical_path_string(canonical);
if let Some(override_value) = user_overrides.get(&key) {
return Some(override_value.clone());
}
for (default_key, default_value) in DEFAULT_EXTERNAL_TYPES {
if *default_key == key {
return Some((*default_value).to_string());
}
}
None
}
pub(crate) fn canonical_path_string(path: &TypePath) -> String {
path.segments().join("::")
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::TypePath;
fn tp(segments: &[&str]) -> TypePath {
TypePath::new(segments.iter().map(|s| (*s).to_string()).collect()).expect("non-empty")
}
#[test]
fn default_chrono_datetime_resolves_to_string() {
let overrides = BTreeMap::new();
let path = tp(&["chrono", "DateTime"]);
assert_eq!(resolve(&path, &overrides).as_deref(), Some("string"));
}
#[test]
fn default_uuid_resolves_to_string() {
let overrides = BTreeMap::new();
assert_eq!(resolve(&tp(&["uuid", "Uuid"]), &overrides).as_deref(), Some("string"));
}
#[test]
fn default_serde_json_value_resolves_to_unknown() {
let overrides = BTreeMap::new();
assert_eq!(resolve(&tp(&["serde_json", "Value"]), &overrides).as_deref(), Some("unknown"));
}
#[test]
fn unknown_path_returns_none() {
let overrides = BTreeMap::new();
assert_eq!(resolve(&tp(&["my_crate", "Workout"]), &overrides), None);
}
#[test]
fn user_override_supplements_defaults() {
let mut overrides = BTreeMap::new();
overrides.insert("my_crate::WorkoutId".to_string(), "string".to_string());
assert_eq!(resolve(&tp(&["my_crate", "WorkoutId"]), &overrides).as_deref(), Some("string"));
}
#[test]
fn user_override_wins_on_conflict() {
let mut overrides = BTreeMap::new();
overrides.insert("chrono::DateTime".to_string(), "Moment".to_string());
assert_eq!(resolve(&tp(&["chrono", "DateTime"]), &overrides).as_deref(), Some("Moment"));
}
#[test]
fn user_override_to_unknown_works() {
let mut overrides = BTreeMap::new();
overrides.insert("my_crate::Blob".to_string(), "unknown".to_string());
assert_eq!(resolve(&tp(&["my_crate", "Blob"]), &overrides).as_deref(), Some("unknown"));
}
#[test]
fn all_default_paths_resolve() {
let overrides = BTreeMap::new();
for (path_str, expected) in DEFAULT_EXTERNAL_TYPES {
let segments: Vec<&str> = path_str.split("::").collect();
let path = tp(&segments);
let actual = resolve(&path, &overrides);
assert_eq!(actual.as_deref(), Some(*expected), "default `{path_str}` should resolve");
}
}
}