diff --git a/gen/src/main.rs b/gen/src/main.rs index dba3867..ac0caad 100644 --- a/gen/src/main.rs +++ b/gen/src/main.rs @@ -727,417 +727,3 @@ fn find_enum<'a>(protocol: &'a Protocol, name: &str) -> &'a Enum { .find_map(|interface| interface.enums.iter().find(|e| e.name == name)) .unwrap() } - -fn generate_client_code(protocols: &[Protocol]) -> Result<()> { - let mut generated_path = OpenOptions::new() - .truncate(true) - .write(true) - .create(true) - .open("src/client/protocol.rs")?; - - writeln!(&mut generated_path, "#![allow(unused)]")?; - writeln!(&mut generated_path, "#![allow(async_fn_in_trait)]")?; - - for protocol in protocols { - debug!("Generating client code for \"{}\"", &protocol.name); - - writeln!( - &mut generated_path, - "pub mod {name} {{", - name = &protocol.name - )?; - - // TODO: Generate content - - writeln!(&mut generated_path, "}}")?; - } - - Ok(()) -} - -fn generate_server_code(protocols: &[Protocol]) -> Result<()> { - let mut generated_path = OpenOptions::new() - .truncate(true) - .write(true) - .create(true) - .open("src/server/protocol.rs")?; - - writeln!(&mut generated_path, "#![allow(unused)]")?; - writeln!(&mut generated_path, "#![allow(async_fn_in_trait)]")?; - - for protocol in protocols { - debug!("Generating server code for \"{}\"", &protocol.name); - - if let Some(description) = &protocol.description { - for line in description.lines() { - writeln!(&mut generated_path, r##"#[doc = r#"{}"#]"##, line.trim())?; - } - } - - writeln!( - &mut generated_path, - "pub mod {name} {{", - name = &protocol.name - )?; - - for interface in &protocol.interfaces { - writeln!( - &mut generated_path, - "pub mod {name} {{", - name = interface.name - )?; - - for enu in &interface.enums { - if !enu.bitfield { - let mut variants = String::new(); - let mut match_variants = String::new(); - - for entry in &enu.entries { - let mut prefix = ""; - - if entry.name.chars().next().unwrap().is_numeric() { - prefix = "_" - } - - if let Some(summary) = &entry.summary { - for line in summary.lines() { - let doc = line.trim(); - - let mut c = doc.chars(); - let doc = c.next().unwrap().to_uppercase().collect::() - + c.as_str(); - - writeln!(&mut variants, r##"#[doc = r#"{doc}"#]"##,)?; - } - } - - let name = entry.name.to_upper_camel_case(); - let value = &entry.value; - - variants.push_str(&format!("{prefix}{name} = {value},",)); - - match_variants.push_str(&format!("{value} => Ok(Self::{prefix}{name}),")); - } - - if let Some(description) = &enu.description { - for line in description.lines() { - writeln!(&mut generated_path, r##"#[doc = r#"{}"#]"##, line.trim())?; - } - } - - let mut name = enu.name.to_upper_camel_case(); - - if KEYWORDS.contains(&name.as_str()) { - name = format!("r#{name}") - } - - writeln!( - &mut generated_path, - r#"#[repr(u32)] - #[non_exhaustive] - #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] - pub enum {name} {{{variants}}}"#, - )?; - - writeln!( - &mut generated_path, - r#"impl TryFrom for {name} {{ - type Error = crate::wire::DecodeError; - - fn try_from(v: u32) -> Result {{ - match v {{ - {match_variants} - _ => Err(crate::wire::DecodeError::MalformedPayload) - }} - }} - }}"# - )?; - - // writeln!( - // &mut generated_path, - // r#"impl std::fmt::Display for {name} {{ - // fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {{ - // write!(f, "{{}}", *self as u32) - // }} - // }}"# - // )?; - } else { - let mut variants = String::new(); - - for entry in &enu.entries { - let mut prefix = ""; - - if entry.name.chars().next().unwrap().is_numeric() { - prefix = "_" - } - - if let Some(summary) = &entry.summary { - for line in summary.lines() { - let doc = line.trim(); - - let mut c = doc.chars(); - let doc = c.next().unwrap().to_uppercase().collect::() - + c.as_str(); - - writeln!(&mut variants, r##"#[doc = r#"{doc}"#]"##,)?; - } - } - - variants.push_str(&format!( - "const {prefix}{name} = {value};", - name = entry.name.to_upper_camel_case(), - value = entry.value - )) - } - - if let Some(description) = &enu.description { - for line in description.lines() { - writeln!(&mut generated_path, r##"#[doc = r#"{}"#]"##, line.trim())?; - } - } - - let name = enu.name.to_upper_camel_case(); - - writeln!( - &mut generated_path, - r#"bitflags::bitflags! {{ - #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] - pub struct {name}: u32 {{{variants}}} - }}"#, - )?; - - writeln!( - &mut generated_path, - r#"impl TryFrom for {name} {{ - type Error = crate::wire::DecodeError; - - fn try_from(v: u32) -> Result {{ - Self::from_bits(v).ok_or(crate::wire::DecodeError::MalformedPayload) - }} - }}"# - )?; - } - } - - if let Some(description) = interface.description.as_ref() { - for line in description.lines() { - writeln!(&mut generated_path, r##"#[doc = r#"{}"#]"##, line.trim())?; - } - } - - writeln!( - &mut generated_path, - r#"pub trait {trait_name}: crate::server::Dispatcher {{ - const INTERFACE: &'static str = "{name}"; - const VERSION: u32 = {version}; - - fn into_object(self, id: crate::wire::ObjectId) -> crate::server::Object where Self: Sized - {{ - crate::server::Object::new(id, self) - }} - - async fn handle_request(&self, object: &crate::server::Object, client: &mut crate::server::Client, message: &mut crate::wire::Message) -> crate::server::Result<()> {{ - match message.opcode {{"#, - trait_name = interface.name.to_upper_camel_case(), - name = interface.name, - version = interface.version - )?; - - for (opcode, request) in interface.requests.iter().enumerate() { - let mut args = "object,client,".to_string(); - - for arg in &request.args { - let mut optional = String::new(); - - if !arg.allow_null && arg.is_return_option() { - optional = format!(".ok_or(crate::wire::DecodeError::MalformedPayload)?"); - } - - let mut tryinto = String::new(); - - if arg.r#enum.is_some() { - tryinto.push_str(".try_into()?") - } - - args.push_str(&format!( - "message.{caller}()?{optional}{tryinto},", - caller = arg.to_caller() - )) - } - - let mut name = request.name.to_snek_case(); - - if KEYWORDS.contains(&name.as_str()) { - name = format!("r#{name}") - } - - writeln!( - &mut generated_path, - r#"{opcode} => {{tracing::debug!("{interface_name}#{{}}.{og_name}()", object.id); self.{name}({args}).await}}"#, - og_name = request.name.to_snek_case(), - interface_name = interface.name - )?; - } - - writeln!( - &mut generated_path, - "_ => Err(crate::server::error::Error::UnknownOpcode) }} }}" - )?; - - for request in &interface.requests { - let mut args = - "&self, _object: &crate::server::Object, client: &mut crate::server::Client," - .to_string(); - - for arg in &request.args { - let mut ty = arg - .to_rust_type(arg.find_protocol(&protocols).as_ref().unwrap_or(&protocol)) - .to_string(); - - if arg.allow_null { - ty = format!("Option<{ty}>"); - } - - let mut name = request.name.to_snek_case(); - - if KEYWORDS.contains(&name.as_str()) { - name = format!("r#{name}") - } - - args.push_str(&format!("{name}: {ty},")) - } - - if let Some(description) = request.description.as_ref() { - for line in description.lines() { - writeln!(&mut generated_path, r##"#[doc = r#"{}"#]"##, line.trim())?; - } - } - - let mut name = request.name.to_snek_case(); - - if KEYWORDS.contains(&name.as_str()) { - name = format!("r#{name}") - } - - writeln!( - &mut generated_path, - "async fn {name}({args}) -> crate::server::Result<()>;", - )?; - } - - for (opcode, event) in interface.events.iter().enumerate() { - let mut args = - "&self, _object: &crate::server::Object, client: &mut crate::server::Client," - .to_string(); - let mut build_args = String::new(); - let mut tracing_args = String::new(); - let mut num_tracing_args = 0usize; - - for arg in &event.args { - let mut ty = arg - .to_rust_type(arg.find_protocol(&protocols).as_ref().unwrap_or(&protocol)) - .to_string(); - let build_ty = arg.to_caller(); - let mut name = arg.name.to_snek_case(); - let mut build_name = arg.name.to_snek_case(); - - if KEYWORDS.contains(&name.as_str()) { - name = format!("r#{name}") - } - - if KEYWORDS.contains(&build_name.as_str()) { - build_name = format!("r#{name}") - } - - if let Some((enum_interface, name)) = arg.to_enum_name() { - let e = if let Some(enum_interface) = enum_interface { - protocols - .iter() - .find_map(|protocol| { - protocol - .interfaces - .iter() - .find(|e| e.name == enum_interface) - }) - .unwrap() - .enums - .iter() - .find(|e| e.name == name) - .unwrap() - } else { - find_enum(&protocol, &name) - }; - - if e.bitfield { - build_name.push_str(".bits()"); - } else { - build_name.push_str(" as u32"); - } - } - - if arg.allow_null { - ty = format!("Option<{ty}>"); - } - - if arg.is_return_option() && !arg.allow_null { - build_name = format!("Some({build_name})") - } - - args.push_str(&format!("{name}: {ty},",)); - build_args.push_str(&format!(".put_{build_ty}({build_name})",)); - tracing_args.push_str(&format!("{name},")); - num_tracing_args += 1; - } - - if let Some(description) = event.description.as_ref() { - for line in description.lines() { - writeln!(&mut generated_path, r##"#[doc = r#"{}"#]"##, line.trim())?; - } - } - - let mut name = event.name.to_snek_case(); - - if KEYWORDS.contains(&name.as_str()) { - name = format!("r#{name}") - } - - writeln!( - &mut generated_path, - "async fn {name}({args}) -> crate::server::Result<()> {{", - )?; - - let mut tracing_brackets = String::new(); - (0..num_tracing_args).for_each(|_| tracing_brackets.push_str("{}, ")); - - let _tracing_brackets = tracing_brackets - .strip_suffix(", ") - .unwrap_or(&tracing_brackets); - - writeln!( - &mut generated_path, - r#"tracing::debug!("-> {interface_name}#{{}}.{og_name}()", _object.id); - let (payload,fds) = crate::wire::PayloadBuilder::new() - {build_args} - .build();"#, - og_name = event.name.to_snek_case(), - interface_name = interface.name, - )?; - - writeln!( - &mut generated_path, - r#"client - .send_message(crate::wire::Message::new(_object.id, {opcode}, payload, fds)) - .await - .map_err(crate::server::error::Error::IoError)"# - )?; - - writeln!(&mut generated_path, "}}")?; - } - - writeln!(&mut generated_path, "}} }}")?; - } - writeln!(&mut generated_path, "}}")?; - } - - Ok(()) -}