From 1ef191f442fcca9c54cff28dc946e38133a45086 Mon Sep 17 00:00:00 2001 From: Kurt Wolf Date: Sat, 14 Dec 2024 23:11:17 -0800 Subject: [PATCH] fix #23 --- codegen_rust/src/client.rs | 24 ++++++++++++------------ codegen_rust/src/lib.rs | 10 +++++++--- codegen_rust/src/request.rs | 35 ++++++++++++++++------------------- mir/src/file.rs | 25 ++++++++++++++++++++++++- mir/src/lib.rs | 2 +- mir_rust/src/file.rs | 9 +++++++++ 6 files changed, 69 insertions(+), 36 deletions(-) diff --git a/codegen_rust/src/client.rs b/codegen_rust/src/client.rs index bf44e18..fc95516 100644 --- a/codegen_rust/src/client.rs +++ b/codegen_rust/src/client.rs @@ -8,7 +8,7 @@ use crate::extras::Extras; use hir::{qualified_env_var, AuthLocation, AuthStrategy, HirSpec, Language, Oauth2Auth, ServerStrategy}; use hir::{Config, Operation}; use libninja_macro::rfunction; -use mir::{import, Class, Field, File, Function, Ident, Item, Visibility}; +use mir::{import, Class, Field, File, Function, Ident, Item, Module, Visibility}; use mir_rust::{ToRustCode, ToRustIdent, ToRustType}; /// Generates the client code for a given OpenAPI specification. @@ -86,6 +86,7 @@ pub fn make_lib_rs(spec: &HirSpec, extras: &Extras, cfg: &Config) -> File TokenStream { let name = &operation.name.to_rust_ident(); quote! { #doc - pub fn #name(&self, #(#fn_args),*) -> FluentRequest<'_, request::#request_struct> { + pub fn #name(&self, #(#fn_args),*) -> FluentRequest<'_, #request_struct> { FluentRequest { client: self, - params: request::#request_struct { + params: #request_struct { #(#struct_field_values,)* } } @@ -245,13 +246,13 @@ pub fn build_api_client_method(operation: &Operation) -> TokenStream { } } -pub fn impl_ServiceClient_paths(spec: &HirSpec) -> Vec { - let mut result = vec![]; - for operation in &spec.operations { - result.push(build_api_client_method(operation)); - } - result -} +// pub fn impl_ServiceClient_paths(spec: &HirSpec) -> Vec { +// let mut result = vec![]; +// for operation in &spec.operations { +// result.push(build_api_client_method(operation)); +// } +// result +// } pub fn authenticate_variant(req: &AuthStrategy, opt: &Config) -> TokenStream { let auth_struct = opt.authenticator_name().to_rust_struct(); @@ -324,7 +325,7 @@ pub fn build_Client_authenticate(spec: &HirSpec, opt: &Config) -> TokenStream { pub fn impl_Client(spec: &HirSpec, opt: &Config) -> TokenStream { let client_struct_name = opt.client_name(); - let path_fns = impl_ServiceClient_paths(spec); + // let path_fns = impl_ServiceClient_paths(spec); let security = spec.has_security(); let authenticate = security @@ -334,7 +335,6 @@ pub fn impl_Client(spec: &HirSpec, opt: &Config) -> TokenStream { quote! { impl #client_struct_name { #authenticate - #(#path_fns)* } } } diff --git a/codegen_rust/src/lib.rs b/codegen_rust/src/lib.rs index 2036ce9..37e41fb 100644 --- a/codegen_rust/src/lib.rs +++ b/codegen_rust/src/lib.rs @@ -53,9 +53,13 @@ pub fn generate_rust_library(spec: HirSpec, cfg: Config) -> Result<()> { fn write_lib_rs(path: &Path, mut file: File, m: &mut Modified) -> std::io::Result<()> { let content = fs::read_to_string(&path).unwrap_or_default(); - if content.contains("default_http_client") { - file.items - .retain(|item| !matches!(item, Item::Fn(f) if f.name == "default_http_client")); + let mut c = content.as_str(); + if let Some(p) = c.find("libninja: after") { + c = &c[..p]; + if c.contains("default_http_client") { + file.items + .retain(|item| !matches!(item, Item::Fn(f) if f.name == "default_http_client")); + } } write_with_content(path, file, content, m) } diff --git a/codegen_rust/src/request.rs b/codegen_rust/src/request.rs index 89f0e63..b8c3049 100644 --- a/codegen_rust/src/request.rs +++ b/codegen_rust/src/request.rs @@ -8,11 +8,11 @@ use quote::quote; use regex::Captures; use hir::{Config, HirSpec, Language, Location, Operation, Parameter}; -use mir::{import, Arg, Class, Doc, Field, File, Function, Ident, Import, Item, Ty, Visibility}; +use mir::{import, Arg, Class, Doc, Field, File, Function, Ident, Item, Ty, Visibility}; use mir_rust::{derives_to_tokens, ToRustCode, ToRustIdent, ToRustType}; -use crate::{write_rust, Modified}; +use crate::{client::build_api_client_method, write_rust, Modified}; use std::io::Result; pub fn write_request_module(spec: &HirSpec, cfg: &Config, m: &mut Modified) -> Result<()> { @@ -63,31 +63,24 @@ pub fn make_single_module(operation: &Operation, spec: &HirSpec, cfg: &Config) - let struct_name = request_structs[0].name.clone(); let response = operation.ret.to_rust_type(); let method = Ident(operation.method.clone()); - // let struct_names = request_structs - // .iter() - // .map(|s| s.name.to_string()) - // .collect::>(); - // let request_structs = request_structs - // .into_iter() - // .map(|s| s.to_rust_code()) - // .collect::>(); let url = make_url(&operation); - // modules.push(fname.clone()); - // let mut import = Import::new(&fname, struct_names); - // import.vis = Visibility::Public; - // imports.push(import); let builder_methods = build_request_struct_builder_methods(&operation) .into_iter() .map(|s| s.to_rust_code()); let assign_inputs = assign_inputs_to_request(&operation.parameters); + let output = if operation.ret.is_primitive() { + quote! { #response } + } else { + quote! { crate::model::#response } + }; let impl_block = quote! { impl FluentRequest<'_, #struct_name> { #(#builder_methods)* } impl<'a> ::std::future::IntoFuture for FluentRequest<'a, #struct_name> { - type Output = httpclient::InMemoryResult<#response>; + type Output = httpclient::InMemoryResult<#output>; type IntoFuture = ::futures::future::BoxFuture<'a, Self::Output>; fn into_future(self) -> Self::IntoFuture { @@ -104,18 +97,22 @@ pub fn make_single_module(operation: &Operation, spec: &HirSpec, cfg: &Config) - }; let mut items: Vec> = request_structs.into_iter().map(|s| Item::Class(s)).collect(); items.push(Item::Block(impl_block)); + let client_method = build_api_client_method(operation); + items.push(Item::Block(quote! { + impl crate::#client_name { + #client_method + } + })); File { attributes: vec![], doc: None, imports: vec![ - import!(serde_json, json), - import!("crate::model::*"), import!(crate, FluentRequest), import!(serde, Serialize, Deserialize), import!(httpclient, InMemoryResponseExt), - Import::new("crate", vec![client_name]), ], items, + modules: Vec::new(), } } @@ -151,7 +148,7 @@ pub fn assign_inputs_to_request(inputs: &[Parameter]) -> TokenStream { match input.location { Location::Path => panic!("Should be filtered."), Location::Body => quote! { - r = r.json(json!({#param_key: #value_identifier})); + r = r.json(serde_json::json!({#param_key: #value_identifier})); }, Location::Query => quote! { r = r.query(#param_key, &#value_identifier.to_string()); diff --git a/mir/src/file.rs b/mir/src/file.rs index ccb3790..3231f65 100644 --- a/mir/src/file.rs +++ b/mir/src/file.rs @@ -1,5 +1,5 @@ use crate::interface::Interface; -use crate::{Class, Doc, Enum, Function, Import}; +use crate::{Class, Doc, Enum, Function, Import, Visibility}; pub enum Item { Class(Class), @@ -9,10 +9,32 @@ pub enum Item { Block(T), } +pub struct Module { + pub name: String, + pub vis: Visibility, +} + +impl Module { + pub fn new(name: impl Into) -> Self { + Self { + name: name.into(), + vis: Visibility::Private, + } + } + + pub fn new_pub(name: impl Into) -> Self { + Self { + name: name.into(), + vis: Visibility::Public, + } + } +} + pub struct File { pub attributes: Vec, pub doc: Option, pub imports: Vec, + pub modules: Vec, /// Code that is before function and class declarations pub items: Vec>, } @@ -27,6 +49,7 @@ where doc: None, imports: vec![], items: vec![], + modules: Vec::new(), } } } diff --git a/mir/src/lib.rs b/mir/src/lib.rs index 5f9b55e..2ecc6e4 100644 --- a/mir/src/lib.rs +++ b/mir/src/lib.rs @@ -1,6 +1,6 @@ pub use class::*; pub use doc::{Doc, DocFormat}; -pub use file::{File, Item}; +pub use file::{File, Item, Module}; pub use function::{build_dict, build_struct, Arg, Function}; pub use ident::*; pub use import::*; diff --git a/mir_rust/src/file.rs b/mir_rust/src/file.rs index 7ae86cb..894d36b 100644 --- a/mir_rust/src/file.rs +++ b/mir_rust/src/file.rs @@ -11,6 +11,7 @@ impl ToRustCode for File { doc, mut imports, mut items, + modules, } = self; for m in &mut items { let Item::Class(m) = m else { @@ -21,10 +22,18 @@ impl ToRustCode for File { let imports = imports.into_iter().map(|i| i.to_rust_code()); let doc = doc.to_rust_code(); let items = items.into_iter().map(|f| f.to_rust_code()); + let modules = modules.into_iter().map(|m| { + let vis = m.vis.to_rust_code(); + let name = syn::parse_str::(&m.name).unwrap(); + quote! { + #vis mod #name; + } + }); quote! { #(#annotations)* #doc #(#imports)* + #(#modules)* #(#items)* } }