Skip to content

Commit e2c5299

Browse files
committed
FromProto
1 parent 95645ff commit e2c5299

File tree

3 files changed

+98
-3
lines changed

3 files changed

+98
-3
lines changed

mullvad-management-interface/build.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
fn main() {
2-
tonic_build::compile_protos("proto/management_interface.proto").unwrap();
2+
tonic_build::configure()
3+
//.type_attribute("mullvad_daemon.management_interface.UUID", "#[derive(::mullvad_proc_macro::FromProto)]")
4+
.compile(&["proto/management_interface.proto"], &["proto"])
5+
.unwrap();
36
}

mullvad-proc-macro/src/lib.rs

+59
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,62 @@ mod inner2 {
162162
})
163163
}
164164
}
165+
166+
#[proc_macro_derive(FromProto)]
167+
pub fn from_proto_derive(item: TokenStream) -> TokenStream {
168+
let input = parse_macro_input!(item as DeriveInput);
169+
170+
crate::inner3::derive(input).into()
171+
}
172+
173+
mod inner3 {
174+
175+
use proc_macro2::TokenStream;
176+
use quote::{quote, TokenStreamExt};
177+
use syn::{spanned::Spanned, DeriveInput, Error};
178+
179+
pub(crate) fn derive(input: DeriveInput) -> TokenStream {
180+
if let syn::Data::Struct(data) = &input.data {
181+
derive_for_struct(&input, data).unwrap_or_else(Error::into_compile_error)
182+
} else {
183+
syn::Error::new(
184+
input.span(),
185+
"Deriving `FromProto` is only supported for structs",
186+
)
187+
.into_compile_error()
188+
}
189+
}
190+
191+
pub(crate) fn derive_for_struct(
192+
input: &DeriveInput,
193+
data: &syn::DataStruct,
194+
) -> syn::Result<TokenStream> {
195+
let my_type = &input.ident;
196+
let mut field_conversions = quote! {};
197+
for field in &data.fields {
198+
let Some(name) = &field.ident else {
199+
return Err(syn::Error::new(
200+
field.span(),
201+
"Tuple structs are not currently supported",
202+
));
203+
};
204+
205+
field_conversions.append_all(quote! {
206+
#name: FromProto::from_proto(other.#name),
207+
})
208+
}
209+
210+
// TODO: take proto type as argument
211+
let real_type = quote! { mullvad_types::#my_type };
212+
213+
Ok(quote! {
214+
impl FromProto<#my_type> for #real_type {
215+
fn from_proto(other: #my_type) -> Self {
216+
Self {
217+
#field_conversions
218+
}
219+
}
220+
}
221+
})
222+
}
223+
}

mullvad-proc-macro/tests/struct.rs

+35-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use chrono::DateTime;
44
use mullvad_proc_macro::{IntoProto, UnwrapProto};
5+
use crate::proto::Timestamp;
56

67
#[derive(Debug)]
78
struct RelaySettings;
@@ -85,12 +86,24 @@ impl IntoProto<proto::Timestamp> for chrono::DateTime<chrono::Utc> {
8586
}
8687
}
8788

89+
impl FromProto<proto::AppVersionInfo> for AppVersionInfo {
90+
fn from_proto(other: proto::AppVersionInfo) -> Self {
91+
AppVersionInfo {
92+
latest_beta: other.latest_beta,
93+
latest_stable: other.latest_stable,
94+
suggested_upgrade: other.suggested_upgrade,
95+
supported: other.supported,
96+
}
97+
}
98+
}
99+
88100
pub type AppVersion = String;
89101

90102
mod proto {
91-
use mullvad_proc_macro::IntoProto;
103+
use super::FromProto;
104+
use mullvad_proc_macro::{FromProto, IntoProto};
92105

93-
#[derive(Debug)]
106+
#[derive(Debug, FromProto)]
94107
pub struct AppVersionInfo {
95108
pub supported: bool,
96109
pub latest_stable: String,
@@ -108,6 +121,16 @@ mod proto {
108121
pub seconds: i64,
109122
pub nanos: i32,
110123
}
124+
125+
mod mullvad_types {
126+
#[derive(Debug)]
127+
pub struct AppVersionInfo {
128+
pub supported: bool,
129+
pub latest_stable: String,
130+
pub latest_beta: String,
131+
pub suggested_upgrade: Option<String>,
132+
}
133+
}
111134
}
112135

113136
trait IntoProto<T> {
@@ -120,6 +143,16 @@ impl<T: Into<S>, S> IntoProto<S> for T {
120143
}
121144
}
122145

146+
trait FromProto<T> {
147+
fn from_proto(other: T) -> Self;
148+
}
149+
150+
impl<T: From<S>, S> FromProto<S> for T {
151+
fn from_proto(other: S) -> Self {
152+
Self::from(other)
153+
}
154+
}
155+
123156
#[test]
124157
fn test_generate_into_proto() {
125158
let settings_proto = AppVersionInfo {

0 commit comments

Comments
 (0)