Why Is TryFrom<&str> Not Auto-Implemented for Implementors of FromStr?

I have a trait and an example struct implementation:

pub trait ResourceId: Debug + Clone + Eq + PartialEq + FromStr {}

pub struct ItemId(String);

impl FromStr for ItemId {
    type Err = ParseIdError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("item-") {
            Ok(Self(s.to_string()) 
        } else { 
            Err(...) 
        }
    }
}

impl ResourceId for ItemId {}

I'm using these values with serde, so I'm using TryFrom<&str> in deserialization:

#[derive(Debug, ..., Serialize, Deserialize)]
#[serde(try_from = "&str")]
pub struct ItemId(String);

So I can absolutely do FromStr::<ItemId>::from_str(s) to get an ItemId, but serde compilation fails for the above as TryFrom<&str> is not implemented:

the trait bound `ItemId: TryFrom<&str>` is not satisfied [E0277]
Help: the trait `From<&str>` is not implemented for `ItemId`
Note: required for `&str` to implement `Into<ItemId>`
Note: required for `ItemId` to implement `TryFrom<&str>`

If I manually implement TryFrom<&str> and use FromStr::from_str as the implementation, it all works.

Due to the orphan rules, I can't do this:

impl<T, E> TryFrom<&str> for T where T: FromStr<Err = E> {
    type Error = E;
    
    fn try_from(value: &str) -> Result<Self, Self::Error> {
        FromStr::from_str(value)
    }
}

Do I need to manually create all of these TryFrom implementations for all of my ResourceId types? Why does FromStr which is a fallible conversion from &str, not automatically imply TryFrom<&str>?

FromStr came with 1.0 and TryFrom didn't stabilize until 1.34. In the meanwhile, you could write your own implementations for FromStr and From/Into. When TryFrom came along, it came with its blanket implementation based on Into. Adding another blanket implementation would create conflicts with those pre-existing implementations.

Or in shorter form: adding a blanket implementation for your trait at some point later than the trait was introduced is a breaking change.

I didn't try to find a better way for serde specifically, but if you want or need the implementations, yes. (Which is the point where I reach for macros.)

Got it, so essentially this means that std is bound by this and can't add it?

I seem to remember coming across frameworks for better UX for making derive macros, does anyone remember what these are? Every time I've tried in the past I've gotten stuck and overwhelmed.

I don’t think the version history is relevant. The conflict comes from these impls:

impl<T, U> TryFrom<U> for T
where
    U: Into<T>

impl<T, U> Into<U> for T
where
    U: From<T>

// proposed
impl<T, E> TryFrom<&str> for T where T: FromStr<Err = E>

This would mean that if some type implemented both FromStr and From<&str>, then TryFrom would have two conflicting implementations for that type. Rust always rejects blanket impls that would allow this type of conflict to occur:

trait Foo {}
trait Bar {}
trait Baz {}

impl<T: Foo> Baz for T {}
impl<T: Bar> Baz for T {}
error[E0119]: conflicting implementations of trait `Baz`
 --> src/lib.rs:6:1
  |
5 | impl<T: Foo> Baz for T {}
  | ---------------------- first implementation here
6 | impl<T: Bar> Baz for T {}
  | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation

what do you want exactly?

for simple cases, you can use macro_rules to generate the derived impls, with the help of macro_rules_attribute, see the examples in the documentation:

Do you mean proc_macro2 which gives more flexibility in how you structure your code, write unit tests etc? Or something less "fundamental"?

(Blatant plug: for nicer compiler errors from your macros I recently created proc_macro2_diagnostic)