1use std::{
2 fs::File,
3 io::Read,
4 path::Path
5};
6use heck::ToSnakeCase;
7use proc_macro2::{TokenStream, Ident, Span};
8use quote::quote;
9use serde::Deserialize;
10
11use crate::Result;
12
13#[derive(Debug, Deserialize)]
14pub struct Protocol {
15 pub name: String,
16 pub summary: Option<String>,
17 pub description: Option<String>,
18 pub copyright: Option<String>,
19 #[serde(rename = "interface", default)]
20 pub interfaces: Vec<Interface>
21}
22impl Protocol {
23 pub fn from_str(string: &str) -> Result<Self> {
24 Ok(toml::from_str(string)?)
25 }
26 pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
27 let path = path.as_ref();
28 let mut protocol = String::new();
29 let mut file = File::open(path)?;
30 file.read_to_string(&mut protocol)?;
31 Ok(Self::from_str(&protocol)?)
32 }
33}
34
35#[derive(Clone, Debug, Deserialize)]
36pub struct Interface {
37 pub name: String,
38 pub summary: Option<String>,
39 pub description: Option<String>,
40 pub version: u32,
41 #[serde(rename = "enum", default)]
42 pub enums: Vec<Enum>,
43 #[serde(rename = "request", default)]
44 pub requests: Vec<Request>,
45 #[serde(rename = "event", default)]
46 pub events: Vec<Event>
47}
48
49#[derive(Clone, Debug, Deserialize)]
50pub struct Enum {
51 pub name: String,
52 pub summary: Option<String>,
53 pub description: Option<String>,
54 pub since: Option<u32>,
55 #[serde(rename = "entry", default)]
56 pub entries: Vec<Entry>
57}
58#[derive(Clone, Debug, Deserialize)]
59pub struct Request {
60 pub name: String,
61 pub since: Option<u32>,
62 #[serde(default)]
63 pub destructor: bool,
64 pub summary: Option<String>,
65 pub description: Option<String>,
66 #[serde(rename = "arg", default)]
67 pub args: Vec<Arg>
68}
69#[derive(Clone, Debug, Deserialize)]
70pub struct Event {
71 pub name: String,
72 pub since: Option<u32>,
73 pub summary: Option<String>,
74 pub description: Option<String>,
75 #[serde(rename = "arg", default)]
76 pub args: Vec<Arg>
77}
78
79#[derive(Clone, Debug, Deserialize)]
80pub struct Entry {
81 pub name: String,
82 pub since: Option<u32>,
83 pub summary: Option<String>,
84 pub description: Option<String>,
85 pub value: u32
86}
87
88#[derive(Clone, Debug, Deserialize)]
89#[serde(rename_all = "lowercase")]
90pub enum RequestType {
91 Destructor
92}
93
94#[derive(Clone, Debug, Deserialize)]
95pub struct Arg {
96 pub name: String,
97 #[serde(rename = "allow-null", default)]
98 pub nullable: bool,
99 #[serde(rename = "type")]
100 pub ty: DataType,
101 pub interface: Option<String>,
102 #[serde(rename = "enum")]
103 pub enumeration: Option<String>,
104 pub summary: Option<String>
105}
106impl Arg {
107 pub fn getter(&self, stream: &Ident) -> TokenStream {
108 match self.ty {
109 DataType::Int => quote!{#stream.i32()?},
110 DataType::Uint => quote!{#stream.u32()?},
111 DataType::Fixed => quote!{#stream.fixed()?},
112 DataType::String => if self.nullable {
113 quote!{#stream.string()?}
114 } else {
115 quote!{#stream.string()?.ok_or(::yutani::wire::WlError::NON_NULLABLE)?}
116 },
117 DataType::Array => quote!{#stream.bytes()?},
118 DataType::Fd => quote!{#stream.file()?},
119 DataType::Object => if self.nullable {
120 quote!{#stream.object()?}
121 } else {
122 quote!{#stream.object()?.ok_or(::yutani::wire::WlError::NON_NULLABLE)?}
123 },
124 DataType::NewId => if let Some(_) = self.interface.as_ref() {
125 quote!{#stream.object()?.ok_or(::yutani::wire::WlError::NON_NULLABLE)?}
126 } else {
127 quote!{#stream.new_id()?}
128 }
129 }
130 }
131 pub fn sender(&self, stream: &Ident) -> TokenStream {
132 let ident = Ident::new_raw(&self.name.to_snake_case(), Span::call_site());
133 match self.ty {
134 DataType::Int => quote!{#stream.send_i32(#ident)?},
135 DataType::Uint => quote!{#stream.send_u32(#ident)?},
136 DataType::Fixed => quote!{#stream.send_fixed(#ident)?},
137 DataType::String => if self.nullable {
138 quote!{#stream.send_string(#ident)?}
139 } else {
140 quote!{#stream.send_string(::core::option::Option::Some(#ident))?}
141 },
142 DataType::Array => quote!{#stream.send_bytes(#ident)?},
143 DataType::Fd => quote!{#stream.send_file(#ident)?},
144 DataType::Object => if self.nullable {
145 quote!{#stream.send_object(#ident)?}
146 } else {
147 quote!{#stream.send_object(Some(#ident))?}
148 },
149 DataType::NewId => if let Some(_) = self.interface.as_ref() {
150 quote!{#stream.send_object(Some(#ident))?}
151 } else {
152 quote!{#stream.send_new_id(#ident)?}
153 }
154 }
155 }
156 pub fn ty(&self) -> TokenStream {
157 match self.ty {
158 DataType::Int => quote!{::core::primitive::i32},
159 DataType::Uint => quote!{::core::primitive::u32},
160 DataType::Fixed => quote!{::yutani::Fixed},
161 DataType::String => if self.nullable {
162 quote!{::core::option::Option<::std::string::String>}
163 } else {
164 quote!{::std::string::String}
165 },
166 DataType::Array => quote!{::std::vec::Vec<u8>},
167 DataType::Fd => quote!{::yutani::File},
168 DataType::Object => if self.nullable {
169 quote!{::core::option::Option<::yutani::Id>}
170 } else {
171 quote!{::yutani::Id}
172 },
173 DataType::NewId => if let Some(_) = self.interface.as_ref() {
174 quote!{::yutani::Id}
175 } else {
176 quote!{::yutani::NewId}
177 }
178 }
179 }
180 pub fn send_ty(&self) -> TokenStream {
181 match self.ty {
182 DataType::Int => quote!{::core::primitive::i32},
183 DataType::Uint => quote!{::core::primitive::u32},
184 DataType::Fixed => quote!{::yutani::Fixed},
185 DataType::String => if self.nullable {
186 quote!{::core::option::Option<&'_ ::core::primitive::str>}
187 } else {
188 quote!{&'_ ::core::primitive::str}
189 },
190 DataType::Array => quote!{&'_ [::core::primitive::u8]},
191 DataType::Fd => quote!{::yutani::Fd<'static>},
192 DataType::Object => if self.nullable {
193 quote!{::core::option::Option<::yutani::Id>}
194 } else {
195 quote!{::yutani::Id}
196 },
197 DataType::NewId => if let Some(_) = self.interface.as_ref() {
198 quote!{::yutani::Id}
199 } else {
200 quote!{&'_ ::yutani::NewId}
201 }
202 }
203 }
204}
205
206#[derive(Copy, Clone, Debug, Deserialize)]
207#[serde(rename_all = "snake_case")]
208pub enum DataType {
209 Int,
210 Uint,
211 Fixed,
212 String,
213 Array,
214 Fd,
215 Object,
216 NewId
217}