Impl string conversion traits for `CommandString`
After MSRV bump `try_from` usually refers to `TryFrom` method but `CommandString` used inherent one making it confusing and non-idiomatic. This implements `FromStr` and `TryFrom<{stringly type}>` for `CommandString` and deprecates the inherent method in favor of those. To keep the code using `&'static str` efficient it provides `try_from_static` inherent method that only converts from `&'static str`. Closes #1135
This commit is contained in:
parent
57fff47408
commit
405be52f5c
|
@ -10,6 +10,7 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use core::{fmt, iter};
|
use core::{fmt, iter};
|
||||||
|
use core::convert::TryFrom;
|
||||||
|
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use io::Read as _;
|
use io::Read as _;
|
||||||
|
@ -46,8 +47,25 @@ impl CommandString {
|
||||||
///
|
///
|
||||||
/// Returns an error if and only if the string is
|
/// Returns an error if and only if the string is
|
||||||
/// larger than 12 characters in length.
|
/// larger than 12 characters in length.
|
||||||
|
#[deprecated(note = "Use `TryFrom::try_from` or `CommandString::try_from_static`", since = "0.29.0")]
|
||||||
pub fn try_from<S: Into<Cow<'static, str>>>(s: S) -> Result<CommandString, CommandStringError> {
|
pub fn try_from<S: Into<Cow<'static, str>>>(s: S) -> Result<CommandString, CommandStringError> {
|
||||||
let cow = s.into();
|
Self::try_from_static_cow(s.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert `&'static str` to `CommandString`
|
||||||
|
///
|
||||||
|
/// This is more efficient for string literals than non-static conversions because it avoids
|
||||||
|
/// allocation.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if and only if the string is
|
||||||
|
/// larger than 12 characters in length.
|
||||||
|
pub fn try_from_static(s: &'static str) -> Result<CommandString, CommandStringError> {
|
||||||
|
Self::try_from_static_cow(s.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_from_static_cow(cow: Cow<'static, str>) -> Result<CommandString, CommandStringError> {
|
||||||
if cow.len() > 12 {
|
if cow.len() > 12 {
|
||||||
Err(CommandStringError { cow })
|
Err(CommandStringError { cow })
|
||||||
} else {
|
} else {
|
||||||
|
@ -56,6 +74,38 @@ impl CommandString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<String> for CommandString {
|
||||||
|
type Error = CommandStringError;
|
||||||
|
|
||||||
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
|
Self::try_from_static_cow(value.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Box<str>> for CommandString {
|
||||||
|
type Error = CommandStringError;
|
||||||
|
|
||||||
|
fn try_from(value: Box<str>) -> Result<Self, Self::Error> {
|
||||||
|
Self::try_from_static_cow(String::from(value).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a str> for CommandString {
|
||||||
|
type Error = CommandStringError;
|
||||||
|
|
||||||
|
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
||||||
|
Self::try_from_static_cow(value.to_owned().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::str::FromStr for CommandString {
|
||||||
|
type Err = CommandStringError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Self::try_from_static_cow(s.to_owned().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for CommandString {
|
impl fmt::Display for CommandString {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.write_str(self.0.as_ref())
|
f.write_str(self.0.as_ref())
|
||||||
|
@ -264,7 +314,7 @@ impl NetworkMessage {
|
||||||
pub fn command(&self) -> CommandString {
|
pub fn command(&self) -> CommandString {
|
||||||
match *self {
|
match *self {
|
||||||
NetworkMessage::Unknown { command: ref c, .. } => c.clone(),
|
NetworkMessage::Unknown { command: ref c, .. } => c.clone(),
|
||||||
_ => CommandString::try_from(self.cmd()).expect("cmd returns valid commands")
|
_ => CommandString::try_from_static(self.cmd()).expect("cmd returns valid commands")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -523,8 +573,8 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn commandstring_test() {
|
fn commandstring_test() {
|
||||||
// Test converting.
|
// Test converting.
|
||||||
assert_eq!(CommandString::try_from("AndrewAndrew").unwrap().as_ref(), "AndrewAndrew");
|
assert_eq!(CommandString::try_from_static("AndrewAndrew").unwrap().as_ref(), "AndrewAndrew");
|
||||||
assert!(CommandString::try_from("AndrewAndrewA").is_err());
|
assert!(CommandString::try_from_static("AndrewAndrewA").is_err());
|
||||||
|
|
||||||
// Test serializing.
|
// Test serializing.
|
||||||
let cs = CommandString("Andrew".into());
|
let cs = CommandString("Andrew".into());
|
||||||
|
@ -534,7 +584,7 @@ mod test {
|
||||||
let cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
|
let cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
|
||||||
assert!(cs.is_ok());
|
assert!(cs.is_ok());
|
||||||
assert_eq!(cs.as_ref().unwrap().to_string(), "Andrew".to_owned());
|
assert_eq!(cs.as_ref().unwrap().to_string(), "Andrew".to_owned());
|
||||||
assert_eq!(cs.unwrap(), CommandString::try_from("Andrew").unwrap());
|
assert_eq!(cs.unwrap(), CommandString::try_from_static("Andrew").unwrap());
|
||||||
|
|
||||||
let short_cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]);
|
let short_cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]);
|
||||||
assert!(short_cs.is_err());
|
assert!(short_cs.is_err());
|
||||||
|
|
Loading…
Reference in New Issue