diff --git a/easytier/Cargo.toml b/easytier/Cargo.toml index 9594d135..cfa67e98 100644 --- a/easytier/Cargo.toml +++ b/easytier/Cargo.toml @@ -51,6 +51,7 @@ toml = "0.8.12" chrono = { version = "0.4.37", features = ["serde"] } cfg-if = "1.0" +delegate = "0.13.5" itertools = "0.14.0" diff --git a/easytier/src/proto/utils.rs b/easytier/src/proto/utils.rs index c75e57c2..c9ab016e 100644 --- a/easytier/src/proto/utils.rs +++ b/easytier/src/proto/utils.rs @@ -1,4 +1,8 @@ +use delegate::delegate; +use derivative::Derivative; +use derive_more::{Deref, DerefMut, From, IntoIterator}; use prost::Message; +use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; /// Generates a stable digest strictly within the lifecycle of the current process. @@ -18,3 +22,92 @@ pub trait TransientDigest: Message { } impl TransientDigest for S {} + +pub trait MessageModel: + Into + for<'m> TryFrom<&'m Message> +{ +} + +impl MessageModel for Model +where + Message: prost::Message, + Model: Into + for<'m> TryFrom<&'m Message>, +{ +} + +#[derive( + Derivative, + Debug, + Clone, + PartialEq, + Eq, + Hash, + From, + Deref, + DerefMut, + Serialize, + Deserialize, + IntoIterator, +)] +#[derivative(Default(bound = ""))] +#[serde(transparent)] +#[into_iterator(owned, ref, ref_mut)] +pub struct RepeatedMessageModel(Vec); + +impl RepeatedMessageModel { + pub fn into_inner(self) -> Vec { + self.0 + } +} + +impl FromIterator for RepeatedMessageModel { + fn from_iter>(iter: I) -> Self { + Self(iter.into_iter().collect()) + } +} + +impl Extend for RepeatedMessageModel { + delegate! { + to self.0 { + fn extend>(&mut self, iter: T); + } + } +} + +impl AsRef<[Model]> for RepeatedMessageModel { + delegate! { + to self.0 { + fn as_ref(&self) -> &[Model]; + } + } +} + +impl AsMut<[Model]> for RepeatedMessageModel { + delegate! { + to self.0 { + fn as_mut(&mut self) -> &mut [Model]; + } + } +} + +impl<'m, Message, Model> TryFrom<&'m [Message]> for RepeatedMessageModel +where + Message: prost::Message, + Model: MessageModel, +{ + type Error = >::Error; + + fn try_from(value: &'m [Message]) -> Result { + value.iter().map(TryInto::try_into).collect() + } +} + +impl From> for Vec +where + Message: prost::Message, + Model: MessageModel, +{ + fn from(value: RepeatedMessageModel) -> Self { + value.into_iter().map(Into::into).collect() + } +}