3 unstable releases
Uses new Rust 2024
new 0.1.1 | Apr 6, 2025 |
---|---|
0.1.0 | Apr 6, 2025 |
0.0.0 | Apr 4, 2025 |
#683 in Rust patterns
319 downloads per month
10KB
53 lines
Fromage 🧀
A cheesy Rust hack for converting between non-local types.
TL;DR: Allows implementing From
and TryFrom
like traits for non-local types without violating
the orphan rules.
This crate has no dependencies or macros, is no_std
and forbids unsafe
code.
Example
Convert between the two non-local types String
and usize
:
use fromage::{Fromage, TryFromage};
struct X;
impl Fromage<String, X> for usize {
fn fromage(value: String) -> Self {
value.len()
}
}
impl TryFromage<String, X> for usize {
type Error = ();
fn try_fromage(value: String) -> Result<Self, Self::Error> {
Ok(value.len())
}
}
#[test]
fn test() {
assert_eq!(5_usize, usize::fromage(String::from("hello")));
assert_eq!(5_usize, usize::try_fromage(String::from("world")).unwrap());
}
Status
Experimental.
How it works
The orphan rules state that:
> Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only if at least one of the following is true:
>
> - `Trait` is a local trait
> - All of:
> - At least one of the types T0..=Tn must be a local type. Let Ti be the first such type.
> - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti)
Fromage defines the Fromage
and TryFromage
traits that mirror the traits in the standard library, except that they
require an impl
defined additional type parameter X
and therefore fulfil the "At least one of the types T0..=Tn
must be a local type" clause above.
The type parameter X
is not used in the trait methods. It may be
any type provided it is both local
and uncovered, typically
a unit struct. It
may be reused for all Fromage
and TryFromage
implementations within a crate.
The Fromage
and TryFromage
traits define methods named fromage
and try_fromage
respectively to avoid conflicting
with the standard library's From
and TryFrom
traits.
Limitations
The Fromage
and TryFromage
traits defined in this crate are distinct from the standard library's From
and
TryFrom
traits and are not interchangeable. Therefore, if a crate uses the standard library's From
and TryFrom
traits in its public API, you cannot use the Fromage
and TryFromage
traits to implement conversions for the
types required by that crate.
For example, if a crate exposes the following public API then you cannot use an impl Fromage<Foo> for Bar
to
implement the conversion.
pub fn foo(value: impl Into<Bar>) { ... }
Alternatives
Newtype
Typically, a
local newtype
is used to implement the standard library's From
and TryFrom
traits when both types are non-local.
Either:
struct FooWrapper(Foo);
impl From<FooWrapper> for Bar {
fn from(_value: FooWrapper) -> Self {
Bar
}
}
Or:
struct BarWrapper(Bar);
impl From<Foo> for BarWrapper {
fn from(_value: Foo) -> Self {
BarWrapper(Bar)
}
}
Conversion function
Simple conversions functions can be used instead of the From
and TryFrom
traits.
fn convert(_value: Foo) -> Bar {
Bar
}
fn try_convert(_value: Foo) -> Result<Bar, ()> {
Ok(Bar)
}
Local traits
For completeness, the orphan rules allow implementing local MyFrom
and MyTryFrom
traits which may then be used with
non-local types.
This approach is not recommended as it requires a significant amount of boilerplate code whilst sharing the same limitations as the Fromage approach.
License
Fromage is distributed under the terms of the Apache License (Version 2.0).
See LICENSE for details.
Copyright 2025