use serde::Serialize;
#[derive(Debug, Clone, Copy, Serialize)]
pub struct DeriveInfo {
pub derive_name: &'static str,
pub trait_path: &'static str,
pub methods: &'static [&'static str],
pub source: &'static str,
}
#[derive(Debug, Clone, Serialize)]
pub struct DeriveLookup {
pub derive_name: String,
pub known: Option<DeriveInfo>,
}
const WELL_KNOWN: &[DeriveInfo] = &[
DeriveInfo {
derive_name: "Debug",
trait_path: "core::fmt::Debug",
methods: &["fmt"],
source: "std",
},
DeriveInfo {
derive_name: "Clone",
trait_path: "core::clone::Clone",
methods: &["clone", "clone_from"],
source: "std",
},
DeriveInfo {
derive_name: "Copy",
trait_path: "core::marker::Copy",
methods: &[],
source: "std",
},
DeriveInfo {
derive_name: "Default",
trait_path: "core::default::Default",
methods: &["default"],
source: "std",
},
DeriveInfo {
derive_name: "PartialEq",
trait_path: "core::cmp::PartialEq",
methods: &["eq", "ne"],
source: "std",
},
DeriveInfo {
derive_name: "Eq",
trait_path: "core::cmp::Eq",
methods: &[],
source: "std",
},
DeriveInfo {
derive_name: "PartialOrd",
trait_path: "core::cmp::PartialOrd",
methods: &["partial_cmp", "lt", "le", "gt", "ge"],
source: "std",
},
DeriveInfo {
derive_name: "Ord",
trait_path: "core::cmp::Ord",
methods: &["cmp", "max", "min", "clamp"],
source: "std",
},
DeriveInfo {
derive_name: "Hash",
trait_path: "core::hash::Hash",
methods: &["hash", "hash_slice"],
source: "std",
},
DeriveInfo {
derive_name: "Serialize",
trait_path: "serde::ser::Serialize",
methods: &["serialize"],
source: "serde",
},
DeriveInfo {
derive_name: "Deserialize",
trait_path: "serde::de::Deserialize",
methods: &["deserialize"],
source: "serde",
},
DeriveInfo {
derive_name: "Display",
trait_path: "core::fmt::Display",
methods: &["fmt"],
source: "derive_more / thiserror",
},
DeriveInfo {
derive_name: "Error",
trait_path: "std::error::Error",
methods: &["source", "description", "cause"],
source: "thiserror / std",
},
];
pub fn lookup(derive_name: &str) -> Option<DeriveInfo> {
WELL_KNOWN
.iter()
.find(|info| info.derive_name.eq_ignore_ascii_case(derive_name))
.copied()
}
pub fn enrich(derive_name: &str) -> DeriveLookup {
DeriveLookup {
derive_name: derive_name.to_string(),
known: lookup(derive_name),
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
#[test]
fn debug_returns_fmt_method() {
let info = lookup("Debug").expect("Debug is well-known");
assert_eq!(info.trait_path, "core::fmt::Debug");
assert_eq!(info.methods, &["fmt"]);
assert_eq!(info.source, "std");
}
#[test]
fn copy_is_marker_no_methods() {
let info = lookup("Copy").expect("Copy is well-known");
assert!(info.methods.is_empty());
}
#[test]
fn unknown_derive_returns_none() {
assert!(lookup("MyCustomProcMacro").is_none());
}
#[test]
fn enrich_wraps_unknown_with_none() {
let l = enrich("UnknownThing");
assert_eq!(l.derive_name, "UnknownThing");
assert!(l.known.is_none());
}
#[test]
fn enrich_wraps_known() {
let l = enrich("Clone");
assert!(l.known.is_some());
assert_eq!(l.known.unwrap().methods, &["clone", "clone_from"]);
}
}