I'm looking for any solution to allow the expect(value).to.be syntax above.
Keep it simple then:
fn main() {
    expect(4).to.be.equal_to(3);
}
fn expect<T>(actual: T) -> To<T> {
    let be = Be {
        be: Expectation(actual),
    };
    To { to: be }
}
struct To<T> {
    pub to: Be<T>,
}
struct Be<T> {
    pub be: Expectation<T>,
}
struct Expectation<T>(T);
impl<T> Expectation<T> {
    fn equal_to<U>(&self, expected: U)
    where
        U: PartialEq<T>,
    {
        if expected != self.0 {
            panic!("Report error")
        }
    }
}
optionally want to skip [to and be]
use std::{ops::Deref, rc::Rc};
fn main() {
    expect(4).to.be.equal_to(3);
    expect(4).to.equal_to(3);
    expect(4).equal_to(3);
}
fn expect<T>(actual: T) -> Expectation<T> {
    let core = Core(Rc::new(actual));
    let be = Be { core: core.clone() };
    let to = To {
        be,
        core: core.clone(),
    };
    Expectation {
        to,
        core: core.clone(),
    }
}
struct Expectation<T> {
    pub to: To<T>,
    core: Core<T>,
}
impl<T> Deref for Expectation<T> {
    type Target = Core<T>;
    fn deref(&self) -> &Core<T> {
        &self.core
    }
}
struct To<T> {
    pub be: Be<T>,
    core: Core<T>,
}
impl<T> Deref for To<T> {
    type Target = Core<T>;
    fn deref(&self) -> &Core<T> {
        &self.core
    }
}
struct Be<T> {
    core: Core<T>,
}
impl<T> Deref for Be<T> {
    type Target = Core<T>;
    fn deref(&self) -> &Core<T> {
        &self.core
    }
}
struct Core<T>(Rc<T>);
impl<T> Clone for Core<T> {
    fn clone(&self) -> Self {
        Core(self.0.clone())
    }
}
impl<T> Core<T> {
    fn equal_to<U>(&self, expected: U)
    where
        U: PartialEq<T>,
    {
        if expected != *self.0 {
            panic!("Report error")
        }
    }
}
Some macros would reduce duplication, but I was too lazy to actually show that ;-)
When in Rome...
I would try to play to Rust's strengths when designing a test assertions library. To me, this means using traits to allow people to easily add custom assertions.
use crate::testlib::prelude::*;
fn main() {
    expect(4).to(be.equal_to(3));
    expect(4).to(equal_to(3));
}
mod testlib {
    // Shorthand variants that will always be imported.
    // Minimize what's in here to avoid name collisions
    pub mod prelude {
        use super::*;
        pub fn expect<A>(actual: A) -> Expectation<A> {
            Expectation::new(actual)
        }
        #[allow(non_upper_case_globals)]
        pub static be: Be = Be;
        pub fn equal_to<E>(expected: E) -> EqualTo<E> {
            EqualTo::new(expected)
        }
    }
    // All the meat of the implementation. Can be divided up nicely.
    pub trait Assertion<A> {
        fn assert(&self, actual: &A);
    }
    pub struct Expectation<A>(A);
    impl<A> Expectation<A> {
        pub fn new(actual: A) -> Self {
            Expectation(actual)
        }
        pub fn to(&self, a: impl Assertion<A>) {
            a.assert(&self.0)
        }
    }
    pub struct Be;
    impl Be {
        pub fn equal_to<E>(&self, expected: E) -> EqualTo<E> {
            EqualTo::new(expected)
        }
    }
    pub struct EqualTo<E>(E);
    impl<E> EqualTo<E> {
        pub fn new(expected: E) -> Self {
            EqualTo(expected)
        }
    }
    impl<A, E> Assertion<A> for EqualTo<E>
    where
        A: PartialEq<E>,
    {
        fn assert(&self, actual: &A) {
            if *actual != self.0 {
                panic!("report an error")
            }
        }
    }
}
Next steps I'd look into:
- An assertion should probably report failures to some passed-in struct, not panic.
- Add a to_notand/ornot_tonegative matcher.
- Add composition of assertions.