Define trait with codependent default implementations

Suppose I want to introduce a trait with 2 methods, that are dependent on each other in the sense, that one of them can be implemented by default using another. For example:

use std::io;

trait SpecificSerializationStrategy: Sized {
  fn deserialize_slice(bytes: &[u8]) -> Self {
    // IO operations on inmemory buffers are infallible
    Self::deserialize_stream(bytes).unwrap()
  }

  fn deserialize_stream(mut stream: impl io::Read) -> io::Result<Self> {
    let mut bytes = vec![];
    stream.read_to_end(&mut bytes)?;    

    Ok(Self::deserialize_slice(&bytes))
  }
}

This case is not only limited to serializing and quite often can be encountered in some crates (unfortunatly, I cannot remember exact examples of such, but I will update this question as soon as I encounter them).

Obviously, if at least on of the functions is not implemented, this default implementation causes infinite recursion. But when I used this pattern previously, Rust compiler was able to recognize the case and require from implementing types AT LEAST ONE of co-dependent members.

I am not sure, as of what changed, but now, this case of default implementations passes.

Is it compiler change? Or am I missing some specific attribute for trait definition/just doing this pattern incorrectly?

I don't think anything changed in this aspect. This kind of mutual infinite recursion was never forbidden. (It likely never will be – it's theoretically impossible to diagnose with 100% specificity, and forbidding mutual recursion or recursion altogether or even with many false positives would incur a massive tax on usability.)

Maybe your code produced a warning-level lint, and you unknowingly had #![deny(warnings)] in your crate root?

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.