FromStr

FromStr トレイトが実装されていると、 .parse() が利用可能になる。 変換するだけなら TryFrom<&str>From<&str> があれば十分なのだが、一応有用そうであれば実装しておくと良い。


#![allow(unused)]
fn main() {
// 追加の制約のない型の場合。

#[repr(transparent)]
pub struct MyStr(str);

#[derive(Clone)]
pub struct MyString(String);

impl From<&str> for MyString {
    fn from(s: &str) -> Self { unimplemented!() }
}

impl From<Box<str>> for Box<MyStr> {
    fn from(s: Box<str>) -> Self { unimplemented!() }
}

impl std::str::FromStr for MyString {
    type Err = std::convert::Infallible;

    #[inline]
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(s.into())
    }
}

impl std::str::FromStr for Box<MyStr> {
    type Err = std::convert::Infallible;

    #[inline]
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Box::<str>::from(s).into())
    }
}
}

失敗しない変換であれば From で既に実装済のはずなので、そちらに丸投げすればよい。

失敗しない変換のエラー型としては std::convert::Infallible を使う。 これは実行時に値を持てない型で、最適化に強力に貢献するはずである。


#![allow(unused)]
fn main() {
// 追加の制約付きの型の場合。

use std::convert::TryFrom;

struct AsciiError;

#[repr(transparent)]
struct AsciiStr(str);

struct AsciiString(String);

impl TryFrom<&str> for AsciiString {
    type Error = AsciiError;

    fn try_from(s: &str) -> Result<Self, Self::Error> { unimplemented!() }
}

impl TryFrom<&str> for Box<AsciiStr> {
    type Error = AsciiError;

    fn try_from(s: &str) -> Result<Self, Self::Error> { unimplemented!() }
}

impl std::str::FromStr for AsciiString {
    type Err = AsciiError;

    #[inline]
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        TryFrom::try_from(s)
    }
}

impl std::str::FromStr for Box<AsciiStr> {
    type Err = AsciiError;

    #[inline]
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        TryFrom::try_from(s)
    }
}
}

失敗のおそれがあっても、 FromStr は所有権なしの str からの変換専用であるから、変換元の値を保存する必要はなく、 AsciiError で事足りる。