1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
use core::fmt::Formatter; use std::convert::From; use std::fmt::Debug; use std::ops::Deref; use prost::Message; use serde::{de::DeserializeOwned, Serialize}; /// A wrapper struct for a protobuf message type. /// /// This has to exist because `impl<T> Trait for T` requires T to be 'covered' /// by a local type (i.e. Proto<T>), when Self is used (I think). Self _is_ /// used by Extract (Future: ExtractFuture<Item = Self>) which I think is why: /// ```compile_fail /// impl<M, B: BufStream> Extract<B> for M /// where /// M: 'static + Message + MessageWrapper<M> /// { /// type Future = Immediate<M>; /// } /// ``` /// doesn't work. /// /// Niko's excellent [blog post](http://smallcultfollowing.com/babysteps/blog/2015/01/14/little-orphan-impls/) has a full writeup. /// /// The effect of this is that you'll have to specify Proto<Message> instead /// of just Message in your functions within `impl_web!()`. This, in turn hurts /// testability (you have to wrap your Messages to pass them into the endpoint /// functions) and kind of works counter to the PORTs (plain old Rust types) /// philosophy. But, I'm pretty sure it's the best we can do without using /// macros or modifying tower-web. /// /// Into<M> for Proto<M> and From<M> for Proto<M> are implemented to ease the /// pain a little bit. Into<M> for Proto<M> instead of From<Proto<M>> for M /// for the same reasons we aren't just implementing Extract for M. /// /// Deref is also implemented it should be possible to use Proto<M> as an M /// for most everything. /// // If it helps we could also implement Message on Proto though I can't really // fathom why this might help anything right now. pub struct Proto<M: MessagePlus>(pub M); /// A thin trait alias to make stuff more legible. pub trait MessagePlus: Message + DeserializeOwned + Serialize + Default {} impl<M: Message + DeserializeOwned + Serialize + Default> MessagePlus for M {} // trait MessagePlus = Message + DeserializeOwned + Serialize + Default; // For when RFC 1733 lands impl<M: MessagePlus> Default for Proto<M> { fn default() -> Self { Proto::new(M::default()) } } impl<M: MessagePlus> Proto<M> { /// Unwraps the message (of type M) from it's Proto<M> container, consuming /// the container in the process. pub fn move_inner(self) -> M { self.0 } /// Creates a new Proto<M> instance from a message of type M. pub fn new(message: M) -> Self { Proto::<M>(message) } } // Provides (_:&M).into() -> Proto<M> and Proto::<M>::from(_:&M) -> Proto<M> impl<M: MessagePlus> From<M> for Proto<M> { fn from(message: M) -> Self { Self::new(message) } } // // This is bad but I don't know what the right answer is. I'm hoping someone // // replies to this: https://github.com/rust-lang/rust/issues/46205 // // Also, this is the recommended approach in the docs for `Into`. // #[allow(incoherent_fundamental_impls)] // // Provides (_:Proto<M>).into() but probably not M::from(_:Proto<M>) -> M // // I am okay with this for now. // impl<M: MessagePlus> Into<M> for Proto<M> { // fn into(self) -> M { // self.0 // } // } impl<M: MessagePlus> Deref for Proto<M> { type Target = M; fn deref(&self) -> &M { &self.0 } } impl<M: MessagePlus> AsRef<M> for Proto<M> { fn as_ref(&self) -> &M { self.deref() } } impl<M: MessagePlus + Debug> Debug for Proto<M> { fn fmt(&self, f: &mut Formatter) -> Result<(), core::fmt::Error> { self.0.fmt(f) } } impl<M: MessagePlus + Clone> Clone for Proto<M> { fn clone(&self) -> Self { Self(M::clone(&self.0)) } }