Working with trait objects requiring sized

前端 未结 2 1672
北海茫月
北海茫月 2021-01-05 22:01

I\'d like to have a LinkedList of trait object wrapper structs. The inner would be a stream type for either an Ssl or Non-Ssl stream. My hope was to pass the st

2条回答
  •  迷失自我
    2021-01-05 22:26

    You cannot use the HStream type directly; it doesn't represent anything. It's only used to construct derived pointer types, such as &HStream and Box.

    The simplest solution would be to have a LinkedList of Stream>.

    fn main() {
        let mut list = Arc::new(Mutex::new(LinkedList::>>::new()));
    }
    

    Then, we just have to implement HStream for Box.

    impl<'a> HRecv for Box {}
    impl<'a> HSend for Box {}
    impl<'a> AsRawFd for Box {
        fn as_raw_fd(&self) -> RawFd { (&**self).as_raw_fd() }
    }
    impl<'a> HStream for Box {}
    

    Note that this is missing a trait... Clone.

    Clone is not object-safe, which means that it's not possible to create trait object types for that trait, such as &Clone or Box. Clone is not object-safe because its clone method returns Self, which represents the concrete type of the implementor. If you used this method through a trait object, the compiler wouldn't be able to know in advance the type of the result (it could be any of Clone's implementors!).

    Since HStream is a subtrait of Clone, HStream is not object-safe either. The consequence is that we can't implement Clone at all, and types like Box are not legal to use.

    However, we can work around this by making our own, object-safe trait. We can even automatically implement it on types that implement the standard Clone trait.

    pub trait BoxedHStreamClone {
        fn boxed_clone(&self) -> Box;
    }
    
    // Implementation for all types that implement HStream and Clone and don't hold any borrows
    impl BoxedHStreamClone for T {
        fn boxed_clone(&self) -> Box {
            Box::new(self.clone()) as Box
        }
    }
    
    // Implementation for Box, which cannot implement Clone
    impl<'a> BoxedHStreamClone for Box {
        fn boxed_clone(&self) -> Box {
            Box::new((&**self).boxed_clone()) as Box
        }
    }
    

    Replace the Clone trait bound on HStream with BoxedHStreamClone and you're good to go!

    pub trait HStream: HRecv + HSend + AsRawFd + BoxedHStreamClone {}
    

    Here's the final code:

    use std::sync::{Arc, Mutex};
    use std::collections::LinkedList;
    use std::os::unix::io::{RawFd, AsRawFd};
    
    pub trait BoxedHStreamClone {
        fn boxed_clone(&self) -> Box;
    }
    
    impl BoxedHStreamClone for T {
        fn boxed_clone(&self) -> Box {
            Box::new(self.clone()) as Box
        }
    }
    
    pub trait HRecv {}
    pub trait HSend {}
    pub trait HStream: HRecv + HSend + AsRawFd + BoxedHStreamClone {}
    pub struct Stream {
        pub inner: T
    }
    
    pub type StreamList = Arc>>>>;
    
    impl<'a> HRecv for Box {}
    impl<'a> HSend for Box {}
    
    impl<'a> AsRawFd for Box {
        fn as_raw_fd(&self) -> RawFd { (&**self).as_raw_fd() }
    }
    
    impl<'a> BoxedHStreamClone for Box {
        fn boxed_clone(&self) -> Box {
            Box::new((&**self).boxed_clone()) as Box
        }
    }
    
    impl<'a> HStream for Box {}
    
    fn main() {
        let mut list = Arc::new(Mutex::new(LinkedList::>>::new()));
    }
    

提交回复
热议问题