Implemented generics properly, updated cpp generator to use operator<< and operator>> for json parsing
This commit is contained in:
		| @@ -8,7 +8,7 @@ pub enum Types { | |||||||
|     Array(Box<Types>), |     Array(Box<Types>), | ||||||
|     Optional(Box<Types>), |     Optional(Box<Types>), | ||||||
|     Named(String), |     Named(String), | ||||||
|     Generic(String, Box<Types>, proc_macro2::Span) |     Generic(String, Vec<Types>) | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, Clone, Default)] | #[derive(Debug, Clone, Default)] | ||||||
| @@ -27,8 +27,7 @@ pub struct FieldTy { | |||||||
| pub struct StructTy { | pub struct StructTy { | ||||||
|     pub name: String, |     pub name: String, | ||||||
|     pub fields: Vec<FieldTy>, |     pub fields: Vec<FieldTy>, | ||||||
|     pub generic_fields: Vec<FieldTy>, |     pub generic_names: Vec<String> | ||||||
|     pub generic_name: Option<String> |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, Clone, Default)] | #[derive(Debug, Clone, Default)] | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ pub const JSON_INNER_IMPLS: &[(&str, &str)] = &[ | |||||||
|  |  | ||||||
| pub fn ty_to_str(ty: &crate::data::Types) -> String { | pub fn ty_to_str(ty: &crate::data::Types) -> String { | ||||||
|     use crate::data::Types; |     use crate::data::Types; | ||||||
|     match &ty { |     match ty { | ||||||
|         Types::String => "std::string".into(), |         Types::String => "std::string".into(), | ||||||
|         Types::Bool => "bool".into(), |         Types::Bool => "bool".into(), | ||||||
|         Types::F32 => "std::float_t".into(), |         Types::F32 => "std::float_t".into(), | ||||||
| @@ -34,10 +34,35 @@ pub fn ty_to_str(ty: &crate::data::Types) -> String { | |||||||
|         Types::Named(name) => name.into(), |         Types::Named(name) => name.into(), | ||||||
|         Types::Optional(inner) => format!("std::optional<{}>", ty_to_str(inner)), |         Types::Optional(inner) => format!("std::optional<{}>", ty_to_str(inner)), | ||||||
|         Types::Array(inner) => format!("std::vector<{}>", ty_to_str(inner)), |         Types::Array(inner) => format!("std::vector<{}>", ty_to_str(inner)), | ||||||
|         Types::Generic(_, _, _) => unreachable!() |         Types::Generic(name, types) => | ||||||
|  |             format!("{}<{}>", name, types.iter().map(|ty| ty_to_str(ty)).join(", ")) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | pub fn get_struct_generics(s: &crate::data::StructTy) -> String { | ||||||
|  |     if s.generic_names.is_empty() { | ||||||
|  |         "".into() | ||||||
|  |     } else { | ||||||
|  |         format!("template<{}>\n", generics_brace_inner_typename(s)) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn generics_brace_inner_typename(s: &crate::data::StructTy) -> String { | ||||||
|  |     s.generic_names.iter().map(|n| String::from("typename ") + n).join(", ") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn generics_brace(s: &crate::data::StructTy) -> String { | ||||||
|  |     if s.generic_names.is_empty() { | ||||||
|  |         "".into() | ||||||
|  |     } else { | ||||||
|  |         format!("<{}>", generics_brace_inner(s)) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn generics_brace_inner(s: &crate::data::StructTy) -> String { | ||||||
|  |     s.generic_names.iter().join(", ") | ||||||
|  | } | ||||||
|  |  | ||||||
| pub fn method_args(method: &crate::data::MethodTy) -> String { | pub fn method_args(method: &crate::data::MethodTy) -> String { | ||||||
|     method.args.iter() |     method.args.iter() | ||||||
|         .map(|arg| format!("{} &&{}", ty_to_str(&arg.ty), arg.name)) |         .map(|arg| format!("{} &&{}", ty_to_str(&arg.ty), arg.name)) | ||||||
| @@ -60,38 +85,6 @@ pub fn call_args(method: &crate::data::MethodTy) -> String { | |||||||
|         .join(", ") |         .join(", ") | ||||||
| } | } | ||||||
|  |  | ||||||
| pub fn json_write(ty: &crate::data::FieldTy) -> String { |  | ||||||
|     use crate::data::Types; |  | ||||||
|     match &ty.ty { |  | ||||||
|         Types::String => format!("__w.String({});", ty.name), |  | ||||||
|         Types::Bool => format!("__w.Bool({});", ty.name), |  | ||||||
|         Types::F32 | Types::F64 => format!("__w.Double({});", ty.name), |  | ||||||
|         Types::I8 | Types::I16 | Types::I32 | Types::I64 => format!("__w.Int64({});", ty.name), |  | ||||||
|         Types::U8 | Types::U16 | Types::U32 | Types::U64 => format!("__w.Uint64({});", ty.name), |  | ||||||
|         Types::Named(_) => format!("{} >> __w;", ty.name), |  | ||||||
|         Types::Optional(inner) => { |  | ||||||
|             let inner = crate::data::FieldTy { name: format!("({}.value())", ty.name), ty: (**inner).clone() }; |  | ||||||
|             let inner = json_write(&inner); |  | ||||||
|             format!( |  | ||||||
| "if ({}.has_value()) {{ |  | ||||||
|         {} |  | ||||||
|     }} else __w.Null();", ty.name, inner) |  | ||||||
|         }, |  | ||||||
|         Types::Array(inner) => { |  | ||||||
|             let inner_var_name = format!("__{}__entry", ty.name); |  | ||||||
|             let inner = crate::data::FieldTy { name: inner_var_name.clone(), ty: (**inner).clone() }; |  | ||||||
|             let inner = json_write(&inner); |  | ||||||
|             format!( |  | ||||||
| "__w.StartArray(); |  | ||||||
|     for (const auto &{} : {}) {{ |  | ||||||
|         {} |  | ||||||
|     }} |  | ||||||
|     __w.EndArray();", inner_var_name, ty.name, inner) |  | ||||||
|         }, |  | ||||||
|         Types::Generic(_, _, _) => unreachable!() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| pub fn streams_required(rpc: &RPC) -> Vec<String> { | pub fn streams_required(rpc: &RPC) -> Vec<String> { | ||||||
|     let mut streams = std::collections::HashSet::new(); |     let mut streams = std::collections::HashSet::new(); | ||||||
|     for s in &rpc.services { |     for s in &rpc.services { | ||||||
| @@ -105,10 +98,10 @@ pub fn streams_required(rpc: &RPC) -> Vec<String> { | |||||||
| } | } | ||||||
|  |  | ||||||
| pub fn gen(file_base_name: &std::path::PathBuf, rpc: &RPC) { | pub fn gen(file_base_name: &std::path::PathBuf, rpc: &RPC) { | ||||||
|     let header_name = file_base_name.with_extension("h"); |     let header_name = file_base_name.with_extension("hxx"); | ||||||
|  |     let h = std::fs::File::create(&header_name).unwrap(); | ||||||
|     let header_name = header_name.file_name().unwrap().to_str().unwrap(); |     let header_name = header_name.file_name().unwrap().to_str().unwrap(); | ||||||
|     let h = std::fs::File::create(file_base_name.with_extension("h")).unwrap(); |     let c = std::fs::File::create(file_base_name.with_extension("cxx")).unwrap(); | ||||||
|     let c = std::fs::File::create(file_base_name.with_extension("cpp")).unwrap(); |     crate::templates::cpp_server_hxx(h, rpc).unwrap(); | ||||||
|     crate::templates::cpp_server_h(h, rpc).unwrap(); |     crate::templates::cpp_server_cxx(c, header_name, rpc).unwrap(); | ||||||
|     crate::templates::cpp_server_cpp(c, header_name, rpc).unwrap(); |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -13,7 +13,16 @@ pub fn ty_to_str(ty: &crate::data::Types) -> String { | |||||||
|         Types::Named(name) => name.into(), |         Types::Named(name) => name.into(), | ||||||
|         Types::Optional(inner) => format!("({}|null)", ty_to_str(inner)), |         Types::Optional(inner) => format!("({}|null)", ty_to_str(inner)), | ||||||
|         Types::Array(inner) => format!("{}[]", ty_to_str(inner)), |         Types::Array(inner) => format!("{}[]", ty_to_str(inner)), | ||||||
|         Types::Generic(_, _, _) => unreachable!() |         Types::Generic(name, types) => | ||||||
|  |             format!("{}<{}>", name, types.iter().map(|ty| ty_to_str(ty)).join(", ")) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn get_struct_generics(s: &crate::data::StructTy) -> String { | ||||||
|  |     if s.generic_names.is_empty() { | ||||||
|  |         "".into() | ||||||
|  |     } else { | ||||||
|  |         format!("<{}>", s.generic_names.join(", ")) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										94
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										94
									
								
								src/main.rs
									
									
									
									
									
								
							| @@ -3,7 +3,6 @@ mod generators; | |||||||
| mod templates; | mod templates; | ||||||
| mod parser; | mod parser; | ||||||
|  |  | ||||||
| use std::collections::HashMap; |  | ||||||
| use std::fmt::Write; | use std::fmt::Write; | ||||||
| use std::fs::File; | use std::fs::File; | ||||||
| use std::io::Read; | use std::io::Read; | ||||||
| @@ -30,95 +29,6 @@ struct GenArgs { | |||||||
| static SOURCE_FILE: once_cell::sync::OnceCell<String> = once_cell::sync::OnceCell::new(); | static SOURCE_FILE: once_cell::sync::OnceCell<String> = once_cell::sync::OnceCell::new(); | ||||||
| static SOURCE: once_cell::sync::OnceCell<String> = once_cell::sync::OnceCell::new(); | static SOURCE: once_cell::sync::OnceCell<String> = once_cell::sync::OnceCell::new(); | ||||||
|  |  | ||||||
| fn has_generic(ty: &mut data::Types) -> Option<&mut data::Types> { |  | ||||||
|     use data::Types; |  | ||||||
|     match ty { |  | ||||||
|         Types::String | Types::Bool | |  | ||||||
|         Types::F32 | Types::F64 | |  | ||||||
|         Types::I8 | Types::I16 | Types::I32 | Types::I64 | |  | ||||||
|         Types::U8 | Types::U16 | Types::U32 | Types::U64 => None, |  | ||||||
|         Types::Array(inner) => has_generic(inner), |  | ||||||
|         Types::Optional(inner) => has_generic(inner), |  | ||||||
|         Types::Named(_) => None, |  | ||||||
|         Types::Generic(_, _, _) => Some(ty) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| pub fn gen_generic_name(ty: &data::Types) -> String { |  | ||||||
|     use data::Types; |  | ||||||
|     match &ty { |  | ||||||
|         Types::String => "string".into(), |  | ||||||
|         Types::Bool => "bool".into(), |  | ||||||
|         Types::F32 => "f32".into(), |  | ||||||
|         Types::F64 => "f64".into(), |  | ||||||
|         Types::I8 => "i8".into(), |  | ||||||
|         Types::I16 => "i16".into(), |  | ||||||
|         Types::I32 => "i32".into(), |  | ||||||
|         Types::I64 => "i64".into(), |  | ||||||
|         Types::U8 => "u8".into(), |  | ||||||
|         Types::U16 => "u16".into(), |  | ||||||
|         Types::U32 => "u32".into(), |  | ||||||
|         Types::U64 => "u64".into(), |  | ||||||
|         Types::Named(name) => name.clone(), |  | ||||||
|         Types::Optional(inner) => format!("maybe_{}", gen_generic_name(inner)), |  | ||||||
|         Types::Array(inner) => format!("array_{}", gen_generic_name(inner)), |  | ||||||
|         Types::Generic(_, _, span) => emit_error(Some((span.clone(), "Nested custom generics are not allowed"))) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| fn replace_generics<'a>(it: impl Iterator<Item=&'a mut data::Types>, generics: &HashMap<String, data::StructTy>, new_structs: &mut HashMap<String, (data::StructTy, data::Types)>) { |  | ||||||
|     for ty in it.filter_map(|ty| has_generic(ty)) { |  | ||||||
|         let (name, inner, span) = match ty { |  | ||||||
|             data::Types::Generic(name, inner, span) => |  | ||||||
|                 (name.clone(), inner.clone(), span.clone()), |  | ||||||
|             _ => unreachable!() |  | ||||||
|         }; |  | ||||||
|         let generic = match generics.get(&name) { |  | ||||||
|             Some(v) => v, |  | ||||||
|             None => emit_error(Some((span, "Type does not exists"))) |  | ||||||
|         }; |  | ||||||
|         let new_name = format!("{}_{}", name, gen_generic_name(&inner)); |  | ||||||
|         *ty = data::Types::Named(new_name.clone()); |  | ||||||
|         new_structs.insert(new_name, (generic.clone(), *inner)); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| fn replace_generic_type(ty: &mut data::Types, generic_name: &String, replacement: &data::Types) { |  | ||||||
|     use data::Types; |  | ||||||
|     match ty { |  | ||||||
|         Types::Named(name) => if name == generic_name { *ty = replacement.clone(); } else { unreachable!() }, |  | ||||||
|         Types::Optional(inner) => replace_generic_type(inner, generic_name, replacement), |  | ||||||
|         Types::Array(inner) => replace_generic_type(inner, generic_name, replacement), |  | ||||||
|         _ => unreachable!() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| fn resolve_generics(rpc: &mut data::RPC) { |  | ||||||
|     let mut generics: HashMap<String, data::StructTy> = HashMap::new(); |  | ||||||
|     rpc.structs.retain(|s| if s.generic_name.is_none() { true } else { |  | ||||||
|         generics.insert(s.name.clone(), s.clone()); |  | ||||||
|         false |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     let mut new_structs = HashMap::new(); |  | ||||||
|     for s in &mut rpc.structs { |  | ||||||
|         replace_generics(s.fields.iter_mut().map(|f| &mut f.ty), &generics, &mut new_structs); |  | ||||||
|     } |  | ||||||
|     for m in &mut rpc.services.iter_mut().map(|s| s.methods.iter_mut()).flatten() { |  | ||||||
|         replace_generics(m.args.iter_mut().map(|f| &mut f.ty).chain(&mut m.ret), &generics, &mut new_structs); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     for (name, (mut generic, inner)) in new_structs { |  | ||||||
|         generic.name = name; |  | ||||||
|         let generic_name = generic.generic_name.take().unwrap(); |  | ||||||
|         for mut field in generic.generic_fields { |  | ||||||
|             replace_generic_type(&mut field.ty, &generic_name, &inner); |  | ||||||
|             generic.fields.push(field); |  | ||||||
|         } |  | ||||||
|         generic.generic_fields = vec![]; |  | ||||||
|         rpc.structs.push(generic); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| fn main() { | fn main() { | ||||||
|     let args = Args::parse(); |     let args = Args::parse(); | ||||||
|  |  | ||||||
| @@ -141,9 +51,7 @@ fn main() { | |||||||
|         ) |         ) | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     let mut rpc = parser::parse_file(&ast); |     let rpc = parser::parse_file(&ast); | ||||||
|  |  | ||||||
|     resolve_generics(&mut rpc); |  | ||||||
|  |  | ||||||
|     for gen in &args.generators.clients { |     for gen in &args.generators.clients { | ||||||
|         gen.generate(&args.rpc_name, &rpc); |         gen.generate(&args.rpc_name, &rpc); | ||||||
|   | |||||||
| @@ -40,20 +40,19 @@ fn parse_type(item: &syn::Type) -> data::Types { | |||||||
|                     syn::PathArguments::AngleBracketed(v) => v, |                     syn::PathArguments::AngleBracketed(v) => v, | ||||||
|                     _ => emit_error(vec![(item.span(), "Angle bracketed arguments expected")]) |                     _ => emit_error(vec![(item.span(), "Angle bracketed arguments expected")]) | ||||||
|                 }; |                 }; | ||||||
|                 if args.args.len() != 1 { |                 let types = args.args.iter().map(|arg| match arg { | ||||||
|                     emit_error(vec![(item.span(), "Expected 1 argument")]); |  | ||||||
|                 } |  | ||||||
|                 let ty = match &args.args[0] { |  | ||||||
|                     syn::GenericArgument::Type(v) => parse_type(v), |                     syn::GenericArgument::Type(v) => parse_type(v), | ||||||
|                     _ => emit_error(vec![(item.span(), "Only types are supported")]) |                     _ => emit_error(vec![(item.span(), "Only types are supported")]) | ||||||
|                 }; |                 }).collect::<Vec<_>>(); | ||||||
|                 let name = segment.ident.to_string(); |                 let name = segment.ident.to_string(); | ||||||
|                 if name == "Option" { |                 if name == "Option" { | ||||||
|                     data::Types::Optional(ty.into()) |                     if types.len() != 1 { emit_error(Some((segment.span(), "Option needs exactly one argument"))); } | ||||||
|  |                     data::Types::Optional(types[0].clone().into()) | ||||||
|                 } else if name == "Vec" { |                 } else if name == "Vec" { | ||||||
|                     data::Types::Array(ty.into()) |                     if types.len() != 1 { emit_error(Some((segment.span(), "Vec needs exactly one argument"))); } | ||||||
|  |                     data::Types::Array(types[0].clone().into()) | ||||||
|                 } else { |                 } else { | ||||||
|                     data::Types::Generic(name, ty.into(), segment.ident.span()) |                     data::Types::Generic(name, types) | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 parse_type_string(segment.ident.to_string()) |                 parse_type_string(segment.ident.to_string()) | ||||||
| @@ -66,20 +65,6 @@ fn parse_type(item: &syn::Type) -> data::Types { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fn has_generic(ty: &data::Types, generic: &String) -> bool { |  | ||||||
|     use data::Types; |  | ||||||
|     match ty { |  | ||||||
|         Types::String | Types::Bool | |  | ||||||
|         Types::F32 | Types::F64 | |  | ||||||
|         Types::I8 | Types::I16 | Types::I32 | Types::I64 | |  | ||||||
|         Types::U8 | Types::U16 | Types::U32 | Types::U64 => false, |  | ||||||
|         Types::Array(inner) => has_generic(inner, generic), |  | ||||||
|         Types::Optional(inner) => has_generic(inner, generic), |  | ||||||
|         Types::Named(name) => name == generic, |  | ||||||
|         Types::Generic(name, inner, _) => name == generic || has_generic(inner, generic) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| fn parse_struct(item: &syn::ItemStruct) -> data::StructTy { | fn parse_struct(item: &syn::ItemStruct) -> data::StructTy { | ||||||
|     let name = item.ident.to_string(); |     let name = item.ident.to_string(); | ||||||
|     if let Some(v) = &item.generics.where_clause { |     if let Some(v) = &item.generics.where_clause { | ||||||
| @@ -88,7 +73,7 @@ fn parse_struct(item: &syn::ItemStruct) -> data::StructTy { | |||||||
|     if item.generics.params.len() > 1 { |     if item.generics.params.len() > 1 { | ||||||
|         emit_error(Some((item.generics.params.span(), "Only one generic parameter is allowed for now"))); |         emit_error(Some((item.generics.params.span(), "Only one generic parameter is allowed for now"))); | ||||||
|     } |     } | ||||||
|     let generic_name = item.generics.params.first().map(|g| { |     let generic_names = item.generics.params.iter().map(|g| { | ||||||
|         match g { |         match g { | ||||||
|             syn::GenericParam::Const(_) | |             syn::GenericParam::Const(_) | | ||||||
|             syn::GenericParam::Lifetime(_) => emit_error(Some((g.span(), "Only generic types are allowed"))), |             syn::GenericParam::Lifetime(_) => emit_error(Some((g.span(), "Only generic types are allowed"))), | ||||||
| @@ -102,23 +87,16 @@ fn parse_struct(item: &syn::ItemStruct) -> data::StructTy { | |||||||
|                 ty.ident.to_string() |                 ty.ident.to_string() | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }); |     }).collect(); | ||||||
|     let mut generic_fields = vec![]; |     let fields = item.fields.iter().map(|field| { | ||||||
|     let mut fields = vec![]; |  | ||||||
|     for field in &item.fields { |  | ||||||
|         if field.ident.is_none() { |         if field.ident.is_none() { | ||||||
|             emit_error(vec![(field.span(), "Missing field name")]); |             emit_error(vec![(field.span(), "Missing field name")]); | ||||||
|         } |         } | ||||||
|         let name = field.ident.as_ref().unwrap().to_string(); |         let name = field.ident.as_ref().unwrap().to_string(); | ||||||
|         let ty = parse_type(&field.ty); |         let ty = parse_type(&field.ty); | ||||||
|         let ty = data::FieldTy { name, ty }; |         data::FieldTy { name, ty } | ||||||
|         if generic_name.is_some() && has_generic(&ty.ty, generic_name.as_ref().unwrap()) { |     }).collect(); | ||||||
|             generic_fields.push(ty); |     data::StructTy { name, fields, generic_names } | ||||||
|         } else { |  | ||||||
|             fields.push(ty); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     data::StructTy { name, fields, generic_fields, generic_name } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| fn try_parse_iterator(ty: &syn::Type) -> Option<data::Types> { | fn try_parse_iterator(ty: &syn::Type) -> Option<data::Types> { | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| @use crate::data::RPC; | @use crate::data::RPC; | ||||||
| @use crate::generators::cpp_s::*; | @use crate::generators::cpp_s::*; | ||||||
| @use super::cpp_server_json_cpp; | @use super::cpp_server_json_cxx; | ||||||
| 
 | 
 | ||||||
| @(header_name: &str, rpc: &RPC) | @(header_name: &str, rpc: &RPC) | ||||||
| #include "@header_name" | #include "@header_name" | ||||||
| @@ -8,7 +8,9 @@ | |||||||
| #include <corvusoft/restbed/resource.hpp> | #include <corvusoft/restbed/resource.hpp> | ||||||
| #include <corvusoft/restbed/request.hpp> | #include <corvusoft/restbed/request.hpp> | ||||||
| 
 | 
 | ||||||
| @:cpp_server_json_cpp(rpc) | using namespace mrpc; | ||||||
|  | 
 | ||||||
|  | @:cpp_server_json_cxx(rpc) | ||||||
| 
 | 
 | ||||||
| template<typename T> | template<typename T> | ||||||
| void send_msg(const std::shared_ptr<restbed::Session> &c, const T &v) @{ | void send_msg(const std::shared_ptr<restbed::Session> &c, const T &v) @{ | ||||||
| @@ -55,7 +57,7 @@ mrpc::MRPCStreamImpl::MRPCStreamImpl(const std::shared_ptr<restbed::Session> &co | |||||||
| 
 | 
 | ||||||
| void mrpc::MRPCStreamImpl::close() const noexcept @{ conn->close("data:null\n\n"); @} | void mrpc::MRPCStreamImpl::close() const noexcept @{ conn->close("data:null\n\n"); @} | ||||||
| bool mrpc::MRPCStreamImpl::is_open() const noexcept @{ return conn->is_open(); @} | bool mrpc::MRPCStreamImpl::is_open() const noexcept @{ return conn->is_open(); @} | ||||||
| @for s in streams_required(rpc) {template<> void MRPCStream<mrpc::@s>::send(const mrpc::@s &v) const noexcept @{ send_sse_msg(conn, v); @} | @for s in streams_required(rpc) {template<> void MRPCStream<@s>::send(const @s &v) const noexcept @{ send_sse_msg(conn, v); @} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| mrpc::MRPCServer::MRPCServer(std::shared_ptr<restbed::Resource> &r) @{ | mrpc::MRPCServer::MRPCServer(std::shared_ptr<restbed::Resource> &r) @{ | ||||||
| @@ -75,7 +77,8 @@ void mrpc::MRPCServer::msg_handler(const std::shared_ptr<restbed::Session> __c, | |||||||
|     if (__j.HasParseError()) |     if (__j.HasParseError()) | ||||||
|         throw std::exception@{@}; |         throw std::exception@{@}; | ||||||
|     std::string __service, __method; |     std::string __service, __method; | ||||||
|     json_get(__j, "service", __service); json_get(__j, "method", __method); |     __service << json_get(__j, "service"); | ||||||
|  |     __method << json_get(__j, "method"); | ||||||
|     auto __data_member = __j.FindMember("data"); |     auto __data_member = __j.FindMember("data"); | ||||||
|     if (__data_member == __j.MemberEnd() || !__data_member->value.IsObject()) |     if (__data_member == __j.MemberEnd() || !__data_member->value.IsObject()) | ||||||
|         throw std::exception@{@}; |         throw std::exception@{@}; | ||||||
| @@ -84,7 +87,7 @@ void mrpc::MRPCServer::msg_handler(const std::shared_ptr<restbed::Session> __c, | |||||||
| @for (mi, m) in s.methods.iter().enumerate() {@if mi > 0 { else }else{        }if (__method == "@m.name") @{ | @for (mi, m) in s.methods.iter().enumerate() {@if mi > 0 { else }else{        }if (__method == "@m.name") @{ | ||||||
|             @if m.ret_stream {auto __stream = MRPCStream<@ty_to_str(m.ret.as_ref().unwrap())>@{__c@}; |             @if m.ret_stream {auto __stream = MRPCStream<@ty_to_str(m.ret.as_ref().unwrap())>@{__c@}; | ||||||
|             } |             } | ||||||
| @for (name, ty) in m.args.iter().map(|a| (&a.name, ty_to_str(&a.ty))) {            @ty @name; json_get<@ty>(__data, "@name", @name); | @for (name, ty) in m.args.iter().map(|a| (&a.name, ty_to_str(&a.ty))) {            @ty @name; @name << json_get(__data, "@name"); | ||||||
|             } |             } | ||||||
|             @if m.ret_stream || m.ret.is_none() {@(s.name)_@(m.name)(@call_args(m));} |             @if m.ret_stream || m.ret.is_none() {@(s.name)_@(m.name)(@call_args(m));} | ||||||
|             else {send_msg(__c, @(s.name)_@(m.name)(@call_args(m)));} |             else {send_msg(__c, @(s.name)_@(m.name)(@call_args(m)));} | ||||||
| @@ -31,10 +31,10 @@ enum struct @e.name : std::uint64_t @{ | |||||||
|     @e.values.iter().map(|(k,v)| format!("{k} = {v}")).join(",\n    ") |     @e.values.iter().map(|(k,v)| format!("{k} = {v}")).join(",\n    ") | ||||||
| @}; | @}; | ||||||
| } | } | ||||||
| @for s in &rpc.structs {struct @s.name; | @for s in &rpc.structs {@get_struct_generics(s)struct @s.name; | ||||||
| } | } | ||||||
| @for s in &rpc.structs { | @for s in &rpc.structs { | ||||||
| struct @s.name @{ | @get_struct_generics(s)struct @s.name @{ | ||||||
| @for f in &s.fields {    @ty_to_str(&f.ty) @f.name; | @for f in &s.fields {    @ty_to_str(&f.ty) @f.name; | ||||||
| } | } | ||||||
|     MRPCJWriter& operator >>(MRPCJWriter&) const; |     MRPCJWriter& operator >>(MRPCJWriter&) const; | ||||||
| @@ -58,6 +58,7 @@ struct MRPCStream final : MRPCStreamImpl @{ | |||||||
| @for s in streams_required(rpc) {template struct MRPCStream<@(s)>; | @for s in streams_required(rpc) {template struct MRPCStream<@(s)>; | ||||||
| }} | }} | ||||||
| struct MRPCServer @{ | struct MRPCServer @{ | ||||||
|  |     MRPCServer() = delete; | ||||||
|     explicit MRPCServer(std::shared_ptr<restbed::Resource>&); |     explicit MRPCServer(std::shared_ptr<restbed::Resource>&); | ||||||
| private: | private: | ||||||
| @for s in &rpc.services {@for m in &s.methods {    virtual @method_ret(m) @(s.name)_@(m.name)(@method_args(m)) = 0; | @for s in &rpc.services {@for m in &s.methods {    virtual @method_ret(m) @(s.name)_@(m.name)(@method_args(m)) = 0; | ||||||
| @@ -1,73 +0,0 @@ | |||||||
| @use crate::data::RPC; |  | ||||||
| @use crate::generators::cpp_s::*; |  | ||||||
|  |  | ||||||
| @(rpc: &RPC) |  | ||||||
| template<typename T> |  | ||||||
| void json_get(const rapidjson::Value &j, const char *key, T &v); |  | ||||||
| template<typename T> |  | ||||||
| void json_get_inner(const rapidjson::Value&, T &v) = delete; |  | ||||||
| @for (ty, jty) in JSON_INNER_IMPLS { |  | ||||||
| template<> inline void json_get_inner(const rapidjson::Value &member, @ty &v) @{ |  | ||||||
|     if (!member.Is@(jty)()) |  | ||||||
|         throw std::exception@{@}; |  | ||||||
|     v = member.Get@(jty)(); |  | ||||||
| @}} |  | ||||||
|  |  | ||||||
| template<typename T> |  | ||||||
| inline void json_get_inner(const rapidjson::Value &member, std::optional<T> &v) @{ |  | ||||||
|     if (member.IsNull()) |  | ||||||
|         v = std::nullopt; |  | ||||||
|     else @{ |  | ||||||
|         T t; |  | ||||||
|         json_get_inner<T>(member, t); |  | ||||||
|         v = std::move(t); |  | ||||||
|     @} |  | ||||||
| @} |  | ||||||
|  |  | ||||||
| template<typename T> |  | ||||||
| inline void json_get_inner(const rapidjson::Value &member, std::vector<T> &v) @{ |  | ||||||
|     if (!member.IsArray()) |  | ||||||
|         throw std::exception@{@}; |  | ||||||
|     for (const auto &j : member.GetArray()) @{ |  | ||||||
|         T t; |  | ||||||
|         json_get_inner<T>(j, t); |  | ||||||
|         v.push_back(std::move(t)); |  | ||||||
|     @} |  | ||||||
| @} |  | ||||||
|  |  | ||||||
| @for s in &rpc.structs { |  | ||||||
| template<> inline void json_get_inner(const rapidjson::Value &__j, mrpc::@s.name &v) @{ |  | ||||||
|     using namespace mrpc; |  | ||||||
| @for f in &s.fields {    json_get<@ty_to_str(&f.ty)>(__j, "@f.name", v.@f.name); |  | ||||||
| }@} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @for e in &rpc.enums { |  | ||||||
| template<> inline void json_get_inner(const rapidjson::Value &j, mrpc::@e.name &v) @{ |  | ||||||
|     json_get_inner<std::uint64_t>(j, (std::uint64_t&)v); |  | ||||||
| @} |  | ||||||
| mrpc::MRPCJWriter& operator >>(const mrpc::@e.name &v, mrpc::MRPCJWriter &w) @{ |  | ||||||
|     w.Uint64((std::uint64_t)v); |  | ||||||
|     return w; |  | ||||||
| @} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename T> |  | ||||||
| inline void json_get(const rapidjson::Value &j, const char *key, T &v) @{ |  | ||||||
|     auto member = j.FindMember(key); |  | ||||||
|     if (member == j.MemberEnd()) |  | ||||||
|         throw std::exception@{@}; |  | ||||||
|     json_get_inner(member->value, v); |  | ||||||
| @} |  | ||||||
|  |  | ||||||
| namespace mrpc @{ |  | ||||||
| @for s in &rpc.structs { |  | ||||||
| MRPCJWriter& @(s.name)::operator >>(MRPCJWriter &__w) const @{ |  | ||||||
|     __w.StartObject(); |  | ||||||
| @for f in &s.fields {    __w.Key("@f.name", @f.name.len()); |  | ||||||
|     @json_write(&f) |  | ||||||
| }    __w.EndObject(); |  | ||||||
|     return __w; |  | ||||||
| @} |  | ||||||
| @(s.name)& @(s.name)::operator <<(const rapidjson::Value &__j) @{ json_get_inner<@(s.name)>(__j, *this); return *this; @} |  | ||||||
| } |  | ||||||
							
								
								
									
										95
									
								
								templates/cpp_server_json.rs.cxx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								templates/cpp_server_json.rs.cxx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | |||||||
|  | @use crate::data::RPC; | ||||||
|  | @use crate::generators::cpp_s::*; | ||||||
|  |  | ||||||
|  | @(rpc: &RPC) | ||||||
|  | @for (ty, jty) in JSON_INNER_IMPLS { | ||||||
|  | inline @(ty)& operator<<(@ty &v, const rapidjson::Value &j) @{ | ||||||
|  |     if (!j.Is@(jty)()) | ||||||
|  |         throw std::exception@{@}; | ||||||
|  |     v = j.Get@(jty)(); | ||||||
|  |     return v; | ||||||
|  | @} | ||||||
|  | inline mrpc::MRPCJWriter& operator>>(const @ty &v, mrpc::MRPCJWriter &w) @{ | ||||||
|  |     w.@(jty)(v); | ||||||
|  |     return w; | ||||||
|  | @}} | ||||||
|  |  | ||||||
|  | @for e in &rpc.enums { | ||||||
|  | inline mrpc::@e.name& operator<<(mrpc::@e.name &v, const rapidjson::Value &j) @{ | ||||||
|  |     ((std::uint64_t&)v) << j; | ||||||
|  |     return v; | ||||||
|  | @} | ||||||
|  | mrpc::MRPCJWriter& operator>>(const mrpc::@e.name &v, mrpc::MRPCJWriter &w) @{ | ||||||
|  |     w.Uint64((std::uint64_t)v); | ||||||
|  |     return w; | ||||||
|  | @} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename T> | ||||||
|  | inline std::vector<T>& operator<<(std::vector<T> &v, const rapidjson::Value &j); | ||||||
|  | template<typename T> | ||||||
|  | inline std::optional<T>& operator<<(std::optional<T> &v, const rapidjson::Value &j) @{ | ||||||
|  |     if (j.IsNull()) | ||||||
|  |         v = std::nullopt; | ||||||
|  |     else @{ | ||||||
|  |         T t; | ||||||
|  |         t << j; | ||||||
|  |         v = std::move(t); | ||||||
|  |     @} | ||||||
|  |     return v; | ||||||
|  | @} | ||||||
|  |  | ||||||
|  | template<typename T> | ||||||
|  | inline std::vector<T>& operator<<(std::vector<T> &v, const rapidjson::Value &j) @{ | ||||||
|  |     if (!j.IsArray()) | ||||||
|  |         throw std::exception@{@}; | ||||||
|  |     for (const auto &e : j.GetArray()) @{ | ||||||
|  |         T t; | ||||||
|  |         t << e; | ||||||
|  |         v.push_back(std::move(t)); | ||||||
|  |     @} | ||||||
|  |     return v; | ||||||
|  | @} | ||||||
|  |  | ||||||
|  | template<typename T> | ||||||
|  | inline mrpc::MRPCJWriter& operator>>(const std::vector<T> &v, mrpc::MRPCJWriter &w); | ||||||
|  | template<typename T> | ||||||
|  | inline mrpc::MRPCJWriter& operator>>(const std::optional<T> &v, mrpc::MRPCJWriter &w) @{ | ||||||
|  |     if (v.has_value()) | ||||||
|  |         v.value() >> w; | ||||||
|  |     else | ||||||
|  |         w.Null(); | ||||||
|  |     return w; | ||||||
|  | @} | ||||||
|  |  | ||||||
|  | template<typename T> | ||||||
|  | inline mrpc::MRPCJWriter& operator>>(const std::vector<T> &v, mrpc::MRPCJWriter &w) @{ | ||||||
|  |     w.StartArray(); | ||||||
|  |     for (const auto &e : v) | ||||||
|  |         e >> w; | ||||||
|  |     w.EndArray(); | ||||||
|  |     return w; | ||||||
|  | @} | ||||||
|  |  | ||||||
|  | inline const rapidjson::Value& json_get(const rapidjson::Value &j, const char *key) @{ | ||||||
|  |     auto member = j.FindMember(key); | ||||||
|  |     if (member == j.MemberEnd()) | ||||||
|  |         throw std::exception@{@}; | ||||||
|  |     return member->value; | ||||||
|  | @} | ||||||
|  |  | ||||||
|  | namespace mrpc @{ | ||||||
|  | @for s in &rpc.structs { | ||||||
|  | @get_struct_generics(s)MRPCJWriter& @(s.name)@(generics_brace(s))::operator>>(MRPCJWriter &__w) const @{ | ||||||
|  |     __w.StartObject(); | ||||||
|  | @for f in &s.fields {    __w.Key("@f.name", @f.name.len()); | ||||||
|  |     @f.name >> __w; | ||||||
|  | }    __w.EndObject(); | ||||||
|  |     return __w; | ||||||
|  | @} | ||||||
|  | @get_struct_generics(s)@(s.name)@(generics_brace(s))& @(s.name)@(generics_brace(s))::operator<<(const rapidjson::Value &__j) @{ | ||||||
|  |     using namespace mrpc; | ||||||
|  | @for f in &s.fields {    @f.name << json_get(__j, "@f.name"); | ||||||
|  | }    return *this; | ||||||
|  | @} | ||||||
|  | } | ||||||
| @@ -10,7 +10,7 @@ export enum @e.name @{ | |||||||
| }@} | }@} | ||||||
| } | } | ||||||
| @for s in &rpc.structs { | @for s in &rpc.structs { | ||||||
| export interface @s.name @{ | export interface @s.name@get_struct_generics(s) @{ | ||||||
| @for f in &s.fields {    @f.name: @ty_to_str(&f.ty); | @for f in &s.fields {    @f.name: @ty_to_str(&f.ty); | ||||||
| }@} | }@} | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user