use alloc::string::String;
use core::fmt;
use core::hash::Hash;
use core::str::FromStr;
pub trait DerivationStyle:
Copy
+ Eq
+ Hash
+ Default
+ fmt::Debug
+ fmt::Display
+ FromStr<Err = ParseDerivationStyleError>
+ 'static
{
fn path(self, index: u32) -> String;
fn name(self) -> &'static str;
fn all() -> &'static [Self];
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct ParseDerivationStyleError {
chain: &'static str,
input: String,
accepted: &'static [&'static str],
}
impl ParseDerivationStyleError {
#[inline]
#[must_use]
pub fn new(
chain: &'static str,
input: impl Into<String>,
accepted: &'static [&'static str],
) -> Self {
Self {
chain,
input: input.into(),
accepted,
}
}
#[inline]
#[must_use]
pub const fn chain(&self) -> &'static str {
self.chain
}
#[inline]
#[must_use]
pub fn input(&self) -> &str {
&self.input
}
#[inline]
#[must_use]
pub const fn accepted(&self) -> &'static [&'static str] {
self.accepted
}
}
impl fmt::Display for ParseDerivationStyleError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"invalid {} derivation style '{}', expected one of: {}",
self.chain,
self.input,
Joined(self.accepted),
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseDerivationStyleError {}
struct Joined<'a>(&'a [&'a str]);
impl fmt::Display for Joined<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut first = true;
for s in self.0 {
if first {
first = false;
} else {
f.write_str(", ")?;
}
f.write_str(s)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use alloc::string::ToString;
use super::*;
#[test]
fn error_display_lists_every_accepted_token() {
let err = ParseDerivationStyleError::new("ethereum", "bogus", &["standard", "live"]);
assert_eq!(
err.to_string(),
"invalid ethereum derivation style 'bogus', expected one of: standard, live"
);
}
#[test]
fn error_accessors_roundtrip() {
let err = ParseDerivationStyleError::new("solana", "bogus", &["a", "b"]);
assert_eq!(err.chain(), "solana");
assert_eq!(err.input(), "bogus");
assert_eq!(err.accepted(), &["a", "b"]);
}
#[test]
fn joined_empty_is_empty() {
assert_eq!(Joined(&[]).to_string(), "");
}
#[test]
fn joined_single_has_no_separator() {
assert_eq!(Joined(&["a"]).to_string(), "a");
}
}