1use std::borrow::Cow;
6use std::fmt::{Display, Formatter, Result as FmtResult};
7use std::io;
8use std::str::FromStr;
9
10use crate::ast;
11use crate::parser::ArgKind;
12
13pub type IoResult = io::Result<()>;
14
15#[derive(Debug)]
16pub enum CodegenTarget {
17 Client,
18 Server,
19}
20
21#[derive(Debug)]
22pub enum ParseCodegenTargetError {
23 TargetNotFound,
24}
25
26impl Display for ParseCodegenTargetError {
27 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
28 write!(f, "{}", "TargetNotFound")
29 }
30}
31
32impl FromStr for CodegenTarget {
33 type Err = ParseCodegenTargetError;
34
35 fn from_str(s: &str) -> Result<Self, Self::Err> {
36 match s {
37 "client" => Ok(CodegenTarget::Client),
38 "server" => Ok(CodegenTarget::Server),
39 _ => Err(ParseCodegenTargetError::TargetNotFound),
40 }
41 }
42}
43
44pub struct Codegen<W: io::Write> {
45 w: W,
46}
47
48impl<W: io::Write> Codegen<W> {
49 pub fn new(w: W) -> Codegen<W> {
50 Codegen { w }
51 }
52
53 pub fn codegen(
54 &mut self,
55 target: CodegenTarget,
56 protocol: ast::Protocol,
57 dependencies: &[String],
58 ) -> IoResult {
59 self.codegen_protocol(target, protocol, dependencies)
60 }
61
62 fn codegen_protocol(
63 &mut self,
64 target: CodegenTarget,
65 protocol: ast::Protocol,
66 dependencies: &[String],
67 ) -> IoResult {
68 writeln!(self.w, "// GENERATED FILE -- DO NOT EDIT")?;
69 if let Some(ref c) = protocol.copyright {
70 writeln!(self.w, "//")?;
71 for line in c.trim().lines() {
72 writeln!(self.w, "// {}", line.trim())?;
73 }
74 }
75 writeln!(
76 self.w,
77 "
78#![allow(warnings)]
79#![allow(clippy::all)]
80use anyhow;
81#[allow(unused_imports)]
82use fuchsia_wayland_core::{{Array, Enum, Fixed, NewId, NewObject}};
83use fuchsia_wayland_core::{{ArgKind, Arg, FromArgs, IntoMessage, Message,
84 MessageGroupSpec, MessageHeader, MessageSpec, MessageType,
85 ObjectId, EncodeError, DecodeError, Interface}};",
86 )?;
87 for dep in dependencies.iter() {
88 writeln!(
89 self.w,
90 "
91#[allow(unused_imports)]
92use {dep}::*;",
93 )?;
94 }
95
96 for interface in protocol.interfaces.into_iter() {
97 writeln!(self.w, "pub mod {} {{", interface.name)?;
112 writeln!(self.w, "use super::*;")?;
113 self.codegen_interface_trait(&target, &interface)?;
114 self.codegen_message_enums(&target, &interface)?;
115 self.codegen_message_traits(&target, &interface)?;
116 self.codegen_enum_types(&interface)?;
117 writeln!(self.w, "}} // mod {}", interface.name)?;
118 writeln!(self.w, "")?;
119 writeln!(self.w, "pub use crate::{}::{};", interface.name, interface.rust_name())?;
120 writeln!(
121 self.w,
122 "pub use crate::{}::Request as {}Request;",
123 interface.name,
124 interface.rust_name()
125 )?;
126 writeln!(
127 self.w,
128 "pub use crate::{}::Event as {}Event;",
129 interface.name,
130 interface.rust_name()
131 )?;
132 }
133 Ok(())
134 }
135
136 fn codegen_message_enums(
150 &mut self,
151 target: &CodegenTarget,
152 interface: &ast::Interface,
153 ) -> IoResult {
154 let enum_descriptions: [(&str, &Vec<ast::Message>, ArgFormatterFn); 2] = match target {
155 CodegenTarget::Client => [
156 ("Request", &interface.requests, format_wire_arg_rust),
157 ("Event", &interface.events, format_dispatch_arg_rust),
158 ],
159 CodegenTarget::Server => [
160 ("Request", &interface.requests, format_dispatch_arg_rust),
161 ("Event", &interface.events, format_wire_arg_rust),
162 ],
163 };
164 for (name, messages, arg_formatter) in enum_descriptions {
165 writeln!(self.w, "#[derive(Debug)]")?;
166 writeln!(self.w, "pub enum {name} {{")?;
167 for message in messages.iter() {
168 if let Some(ref d) = message.description {
169 self.codegen_description(d, " ")?;
170 }
171 if message.args.is_empty() {
172 writeln!(self.w, " {},", message.rust_name())?;
176 } else {
177 writeln!(self.w, " {} {{", message.rust_name())?;
185 for arg in message.args.iter() {
186 if let Some(ref summary) = arg.summary {
187 for line in summary.lines() {
188 writeln!(self.w, " /// {}", line.trim())?;
189 }
190 }
191 writeln!(
192 self.w,
193 " {arg_name}: {arg_type},",
194 arg_name = arg.rust_name(),
195 arg_type = arg_formatter(&arg)
196 )?;
197 }
198 writeln!(self.w, " }},")?;
199 }
200 }
201 writeln!(self.w, "}}")?;
202 writeln!(self.w, "")?;
203
204 writeln!(self.w, "impl MessageType for {} {{", name)?;
205
206 writeln!(self.w, " fn log(&self, this: ObjectId) -> String {{")?;
217 writeln!(self.w, " match *self {{")?;
218 for message in messages.iter() {
219 writeln!(self.w, " {}::{} {{", name, message.rust_name())?;
220 for arg in message.args.iter() {
221 writeln!(self.w, " ref {},", arg.rust_name())?;
222 }
223 writeln!(self.w, " }} => {{")?;
224
225 write!(
236 self.w,
237 " format!(\"{}@{{:?}}::{}(",
238 interface.name, message.name
239 )?;
240 let mut message_args = vec![];
241 let mut format_args: Vec<Cow<'_, str>> = vec!["this".into()];
242 for arg in message.args.iter() {
243 match arg.kind {
244 ArgKind::Array => {
245 message_args.push(format!("{}: Array[{{}}]", arg.name));
246 format_args.push(format!("{}.len()", arg.rust_name()).into());
247 }
248 ArgKind::Fd => {
249 message_args.push(format!("{}: <handle>", arg.name));
250 }
251 _ => {
252 message_args.push(format!("{}: {{:?}}", arg.name));
253 format_args.push(arg.rust_name().into());
254 }
255 }
256 }
257 writeln!(self.w, "{})\", {})", message_args.join(", "), format_args.join(", "))?;
258 writeln!(self.w, " }}")?;
259 }
260 writeln!(self.w, " }}")?;
261 writeln!(self.w, " }}")?;
262
263 writeln!(self.w, " fn message_name(&self) -> &'static std::ffi::CStr{{")?;
264 writeln!(self.w, " match *self {{")?;
265 for message in messages.iter() {
266 writeln!(
267 self.w,
268 " {}::{} {{ .. }} => c\"{}::{}\",",
269 name,
270 message.rust_name(),
271 interface.name,
272 message.name
273 )?;
274 }
275 writeln!(self.w, " }}")?;
276 writeln!(self.w, " }}")?;
277
278 writeln!(self.w, "}}")?;
279 }
280 Ok(())
281 }
282
283 fn codegen_message_traits(
284 &mut self,
285 target: &CodegenTarget,
286 interface: &ast::Interface,
287 ) -> IoResult {
288 let (into_message_name, from_args_name, into_message_messages, from_args_messages) =
289 match target {
290 CodegenTarget::Client => {
291 ("Request", "Event", &interface.requests, &interface.events)
292 }
293 CodegenTarget::Server => {
294 ("Event", "Request", &interface.events, &interface.requests)
295 }
296 };
297
298 self.codegen_into_message(into_message_name, into_message_messages)?;
299 self.codegen_from_args(from_args_name, from_args_messages)?;
300 Ok(())
301 }
302
303 fn codegen_into_message(&mut self, name: &str, messages: &Vec<ast::Message>) -> IoResult {
329 write!(
330 self.w,
331 "\
332impl IntoMessage for {name} {{
333 type Error = EncodeError;
334 fn into_message(self, id: u32) -> Result<Message, <Self as IntoMessage>::Error> {{
335 let mut header = MessageHeader {{
336 sender: id,
337 opcode: 0,
338 length: 0,
339 }};
340 let mut msg = Message::new();
341 msg.write_header(&header)?;
342 match self {{"
343 )?;
344
345 for (op, message) in messages.iter().enumerate() {
346 write!(
347 self.w,
348 "
349 {name}::{message_name} {{\n",
350 message_name = to_camel_case(&message.name)
351 )?;
352 for arg in message.args.iter() {
353 write!(self.w, " {arg_name},\n", arg_name = arg.rust_name())?;
354 }
355 write!(self.w, " }} => {{\n")?;
356 for arg in message.args.iter() {
357 write!(
358 self.w,
359 " msg.write_arg({arg})?;\n",
360 arg = format_wire_arg(&arg, &arg.rust_name())
361 )?;
362 }
363 write!(
364 self.w,
365 " header.opcode = {opcode};
366 }},",
367 opcode = op
368 )?;
369 }
370 write!(
371 self.w,
372 "
373 }}
374 header.length = msg.bytes().len() as u16;
375 msg.rewind();
376 msg.write_header(&header)?;
377 Ok(msg)
378 }}
379}}\n"
380 )
381 }
382
383 fn codegen_from_args(&mut self, name: &str, messages: &Vec<ast::Message>) -> IoResult {
400 write!(
401 self.w,
402 "\
403impl FromArgs for {name} {{
404 fn from_args(op: u16, mut args: Vec<Arg>) -> Result<Self, anyhow::Error> {{
405 match op {{",
406 )?;
407
408 for (op, message) in messages.iter().enumerate() {
409 write!(
410 self.w,
411 "
412 {opcode} /* {op_name} */ => {{
413 let mut iter = args.into_iter();
414 Ok({name}::{message_name} {{\n",
415 opcode = op,
416 op_name = message.name,
417 message_name = to_camel_case(&message.name)
418 )?;
419 for arg in message.args.iter() {
420 writeln!(
421 self.w,
422 " {}: iter.next()
423 .ok_or(DecodeError::InsufficientArgs)?
424 .{},",
425 arg.rust_name(),
426 arg_to_primitive(&arg)
427 )?;
428 }
429 write!(
430 self.w,
431 "
432 }})
433 }},"
434 )?;
435 }
436 write!(
437 self.w,
438 "
439 _ => {{
440 Err(DecodeError::InvalidOpcode(op).into())
441 }},
442 }}
443 }}
444}}\n"
445 )
446 }
447
448 fn codegen_interface_trait(
460 &mut self,
461 target: &CodegenTarget,
462 interface: &ast::Interface,
463 ) -> IoResult {
464 let interface_name = to_camel_case(&interface.name);
465 if let Some(ref d) = interface.description {
466 self.codegen_description(d, "")?;
467 }
468 let (incoming_type, outgoing_type) = match target {
469 CodegenTarget::Client => ("Event", "Request"),
470 CodegenTarget::Server => ("Request", "Event"),
471 };
472 writeln!(self.w, "#[derive(Debug)]")?;
473 writeln!(self.w, "pub struct {};", interface_name)?;
474 writeln!(self.w, "")?;
475 writeln!(self.w, "impl Interface for {} {{", interface_name)?;
476 writeln!(self.w, " const NAME: &'static str = \"{}\";", interface.name)?;
477 writeln!(self.w, " const VERSION: u32 = {};", interface.version)?;
478 write!(self.w, " const REQUESTS: MessageGroupSpec = ")?;
479 self.codegen_message_group_spec(&interface.requests)?;
480 write!(self.w, " const EVENTS: MessageGroupSpec = ")?;
481 self.codegen_message_group_spec(&interface.events)?;
482 writeln!(self.w, " type Incoming = {incoming_type};")?;
483 writeln!(self.w, " type Outgoing = {outgoing_type};")?;
484 writeln!(self.w, "}}")?;
485 writeln!(self.w, "")?;
486 Ok(())
487 }
488
489 fn codegen_message_group_spec(&mut self, messages: &Vec<ast::Message>) -> IoResult {
490 writeln!(self.w, "MessageGroupSpec(&[")?;
491 for m in messages.iter() {
492 writeln!(self.w, " // {}", m.name)?;
493 writeln!(self.w, " MessageSpec(&[")?;
494 for arg in m.args.iter() {
495 writeln!(self.w, " {},", format_arg_kind(&arg))?;
496 }
497 writeln!(self.w, " ]),")?;
498 }
499 writeln!(self.w, " ]);")?;
500 Ok(())
501 }
502
503 fn codegen_enum_types(&mut self, interface: &ast::Interface) -> IoResult {
504 for e in interface.enums.iter() {
505 if e.bitfield {
506 self.codegen_bitflags_enum(e)?;
507 } else {
508 self.codegen_value_enum(e)?;
509 }
510 self.codegen_enum_into_arg(e)?;
511 }
512 Ok(())
513 }
514
515 fn codegen_enum_into_arg(&mut self, e: &ast::Enum) -> IoResult {
516 writeln!(self.w, "impl Into<Arg> for {} {{", e.rust_name())?;
517 writeln!(self.w, " fn into(self) -> Arg {{")?;
518 writeln!(self.w, " Arg::Uint(self.bits())")?;
519 writeln!(self.w, " }}")?;
520 writeln!(self.w, "}}")?;
521 Ok(())
522 }
523
524 fn codegen_value_enum(&mut self, e: &ast::Enum) -> IoResult {
525 if let Some(ref d) = e.description {
526 self.codegen_description(d, "")?;
527 }
528 writeln!(self.w, "#[derive(Copy, Clone, Debug, Eq, PartialEq)]")?;
529 writeln!(self.w, "#[repr(u32)]")?;
530 writeln!(self.w, "pub enum {} {{", e.rust_name())?;
531 for entry in e.entries.iter() {
532 if let Some(ref s) = entry.summary {
533 for l in s.lines() {
534 writeln!(self.w, " /// {},", l.trim())?;
535 }
536 }
537 writeln!(self.w, " {} = {},", entry.rust_name(), entry.value)?;
538 }
539 writeln!(self.w, "}}")?;
540 writeln!(self.w, "")?;
541 writeln!(self.w, "impl {} {{", e.rust_name())?;
542 writeln!(self.w, " pub fn from_bits(v: u32) -> Option<Self> {{")?;
543 writeln!(self.w, " match v {{")?;
544 for entry in e.entries.iter() {
545 writeln!(
546 self.w,
547 " {} => Some({}::{}),",
548 entry.value,
549 e.rust_name(),
550 entry.rust_name()
551 )?;
552 }
553 writeln!(self.w, " _ => None,")?;
554 writeln!(self.w, " }}")?;
555 writeln!(self.w, " }}")?;
556 writeln!(self.w, "")?;
557 writeln!(self.w, " pub fn bits(&self) -> u32 {{")?;
558 writeln!(self.w, " *self as u32")?;
559 writeln!(self.w, " }}")?;
560 writeln!(self.w, "}}")?;
561 Ok(())
562 }
563
564 fn codegen_bitflags_enum(&mut self, e: &ast::Enum) -> IoResult {
565 writeln!(self.w, "::bitflags::bitflags! {{")?;
566 if let Some(ref d) = e.description {
567 self.codegen_description(d, " ")?;
568 }
569 writeln!(
570 self.w,
571 " #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]"
572 )?;
573 writeln!(self.w, " pub struct {}: u32 {{", e.rust_name())?;
574 for entry in e.entries.iter() {
575 if let Some(ref s) = entry.summary {
576 for l in s.lines() {
577 writeln!(self.w, " /// {},", l.trim())?;
578 }
579 }
580 writeln!(self.w, " const {} = {};", entry.rust_name(), entry.value)?;
581 }
582 writeln!(self.w, " }}")?;
583 writeln!(self.w, "}}")?;
584 Ok(())
585 }
586
587 fn codegen_description(&mut self, d: &ast::Description, prefix: &str) -> IoResult {
588 writeln!(self.w, "")?;
589 for s in d.summary.as_str().trim().lines() {
590 writeln!(self.w, "{}/// {}", prefix, s.trim())?;
591 }
592 writeln!(self.w, "{}///", prefix)?;
593 for s in d.description.trim().lines() {
594 writeln!(self.w, "{}/// {}", prefix, s.trim())?;
595 }
596 Ok(())
597 }
598}
599
600fn to_camel_case(s: &str) -> String {
601 s.split('_').filter(|s| s.len() > 0).map(|s| s[..1].to_uppercase() + &s[1..]).collect()
602}
603
604fn enum_path(name: &str) -> String {
626 let parts: Vec<&str> = name.splitn(2, ".").collect();
627 if parts.len() == 1 {
628 to_camel_case(name)
629 } else {
630 format!("crate::{}::{}", parts[0], to_camel_case(parts[1]))
631 }
632}
633
634type ArgFormatterFn = for<'r> fn(&'r ast::Arg) -> Cow<'r, str>;
635
636fn format_dispatch_arg_rust(arg: &ast::Arg) -> Cow<'_, str> {
637 if let Some(ref enum_type) = arg.enum_type {
638 return format!("Enum<{}>", enum_path(enum_type)).into();
639 }
640 match arg.kind {
641 ArgKind::Int => "i32".into(),
642 ArgKind::Uint => "u32".into(),
643 ArgKind::Fixed => "Fixed".into(),
644 ArgKind::String => "String".into(),
645 ArgKind::Object => "ObjectId".into(),
646 ArgKind::NewId => {
647 if let Some(interface) = &arg.interface {
648 format!("NewObject<{}>", to_camel_case(&interface)).into()
649 } else {
650 "ObjectId".into()
651 }
652 }
653 ArgKind::Array => "Array".into(),
654 ArgKind::Fd => "zx::Handle".into(),
655 }
656}
657
658fn format_wire_arg_rust(arg: &ast::Arg) -> Cow<'_, str> {
659 if let Some(ref enum_type) = arg.enum_type {
660 return enum_path(enum_type).into();
661 }
662 match arg.kind {
663 ArgKind::Int => "i32",
664 ArgKind::Uint => "u32",
665 ArgKind::Fixed => "Fixed",
666 ArgKind::String => "String",
667 ArgKind::Object => "ObjectId",
668 ArgKind::NewId => "NewId",
669 ArgKind::Array => "Array",
670 ArgKind::Fd => "zx::Handle",
671 }
672 .into()
673}
674
675fn format_arg_kind(arg: &ast::Arg) -> &'static str {
676 if arg.enum_type.is_some() {
677 return "ArgKind::Uint";
678 }
679 match arg.kind {
680 ArgKind::Int => "ArgKind::Int",
681 ArgKind::Uint => "ArgKind::Uint",
682 ArgKind::Fixed => "ArgKind::Fixed",
683 ArgKind::String => "ArgKind::String",
684 ArgKind::Object => "ArgKind::Object",
685 ArgKind::NewId => "ArgKind::NewId",
686 ArgKind::Array => "ArgKind::Array",
687 ArgKind::Fd => "ArgKind::Handle",
688 }
689}
690
691fn format_wire_arg(arg: &ast::Arg, var: &str) -> String {
692 if arg.enum_type.is_some() {
693 return format!("Arg::Uint({}.bits())", var);
694 }
695 match arg.kind {
696 ArgKind::Int => format!("Arg::Int({})", var),
697 ArgKind::Uint => format!("Arg::Uint({})", var),
698 ArgKind::Fixed => format!("Arg::Fixed({})", var),
699 ArgKind::String => format!("Arg::String({})", var),
700 ArgKind::Object => format!("Arg::Object({})", var),
701 ArgKind::NewId => format!("Arg::NewId({})", var),
702 ArgKind::Array => format!("Arg::Array({})", var),
703 ArgKind::Fd => format!("Arg::Handle({})", var),
704 }
705}
706
707fn arg_to_primitive(arg: &ast::Arg) -> String {
708 if let Some(ref enum_type) = arg.enum_type {
709 return format!(
710 "as_uint().map(|i| match {}::from_bits(i) {{
711 Some(e) => Enum::Recognized(e),
712 None => Enum::Unrecognized(i),
713 }})?",
714 enum_path(enum_type)
715 );
716 }
717 match arg.kind {
718 ArgKind::Int => "as_int()?",
719 ArgKind::Uint => "as_uint()?",
720 ArgKind::Fixed => "as_fixed()?.into()",
721 ArgKind::String => "as_string()?",
722 ArgKind::Object => "as_object()?",
723 ArgKind::NewId => "as_new_id()?.into()",
724 ArgKind::Array => "as_array()?",
725 ArgKind::Fd => "as_handle()?",
726 }
727 .to_string()
728}
729
730trait RustName {
735 fn rust_name(&self) -> String;
736}
737
738impl RustName for ast::EnumEntry {
739 fn rust_name(&self) -> String {
743 let is_digit = self.name.chars().next().map_or(false, |c| c.is_digit(10));
744 let prefix = if is_digit { "_" } else { "" };
745 format!("{}{}", prefix, to_camel_case(&self.name))
746 }
747}
748
749fn is_rust_keyword(s: &str) -> bool {
750 match s {
751 "as" | "break" | "const" | "continue" | "crate" | "dyn" | "else" | "enum" | "extern"
752 | "false" | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "match" | "mod"
753 | "move" | "mut" | "pub" | "ref" | "return" | "Self" | "self" | "static" | "struct"
754 | "super" | "trait" | "true" | "type" | "unsafe" | "use" | "where" | "while"
755 | "abstract" | "async" | "await" | "become" | "box" | "do" | "final" | "macro"
756 | "override" | "priv" | "try" | "typeof" | "unsized" | "virtual" | "yield" => true,
757 _ => false,
758 }
759}
760
761impl RustName for ast::Arg {
762 fn rust_name(&self) -> String {
763 if is_rust_keyword(&self.name) {
764 format!("{}_", self.name)
765 } else {
766 self.name.to_owned()
767 }
768 }
769}
770
771impl RustName for ast::Message {
772 fn rust_name(&self) -> String {
773 to_camel_case(&self.name)
774 }
775}
776
777impl RustName for ast::Enum {
778 fn rust_name(&self) -> String {
779 to_camel_case(&self.name)
780 }
781}
782
783impl RustName for ast::Interface {
784 fn rust_name(&self) -> String {
785 to_camel_case(&self.name)
786 }
787}