diff --git a/crates/dagger-codegen/src/functions.rs b/crates/dagger-codegen/src/functions.rs index 0a55482..7dd8a85 100644 --- a/crates/dagger-codegen/src/functions.rs +++ b/crates/dagger-codegen/src/functions.rs @@ -1,6 +1,8 @@ use std::sync::Arc; -use dagger_core::introspection::{TypeRef, __TypeKind}; +use dagger_core::introspection::{FullType, InputValue, TypeRef, __TypeKind}; + +use crate::utility::OptionExt; pub trait FormatTypeFuncs { fn format_kind_list(&self, representation: &str) -> String; @@ -44,62 +46,66 @@ impl CommonFunctions { let mut representation = String::new(); let mut r = Some(t.clone()); while r.is_some() { - match r.as_ref() { + return match r.as_ref() { Some(rf) => match rf.kind.as_ref() { Some(k) => match k { __TypeKind::SCALAR => match Scalar::from(rf) { - Scalar::Int => { - self.format_type_funcs - .format_kind_scalar_int(&mut representation); - } - Scalar::Float => { - self.format_type_funcs - .format_kind_scalar_float(&mut representation); - } - Scalar::String => { - self.format_type_funcs - .format_kind_scalar_string(&mut representation); - } - Scalar::Boolean => { - self.format_type_funcs - .format_kind_scalar_boolean(&mut representation); - } - Scalar::Default => { - self.format_type_funcs.format_kind_scalar_default( - &mut representation, - rf.name.as_ref().unwrap(), - input, - ); - } + Scalar::Int => self + .format_type_funcs + .format_kind_scalar_int(&mut representation), + Scalar::Float => self + .format_type_funcs + .format_kind_scalar_float(&mut representation), + Scalar::String => self + .format_type_funcs + .format_kind_scalar_string(&mut representation), + Scalar::Boolean => self + .format_type_funcs + .format_kind_scalar_boolean(&mut representation), + Scalar::Default => self.format_type_funcs.format_kind_scalar_default( + &mut representation, + rf.name.as_ref().unwrap(), + input, + ), }, - __TypeKind::OBJECT => { - self.format_type_funcs - .format_kind_object(&mut representation, rf.name.as_ref().unwrap()); - } - __TypeKind::ENUM => { - self.format_type_funcs - .format_kind_enum(&mut representation, rf.name.as_ref().unwrap()); - } + __TypeKind::OBJECT => self + .format_type_funcs + .format_kind_object(&mut representation, rf.name.as_ref().unwrap()), + __TypeKind::ENUM => self + .format_type_funcs + .format_kind_enum(&mut representation, rf.name.as_ref().unwrap()), __TypeKind::INPUT_OBJECT => { self.format_type_funcs.format_kind_input_object( &mut representation, &rf.name.as_ref().unwrap(), - ); + ) } __TypeKind::LIST => { - self.format_type_funcs.format_kind_list(&mut representation); + representation = + self.format_type_funcs.format_kind_list(&mut representation); + r = rf.of_type.as_ref().map(|t| t.clone()).map(|t| *t); + continue; + } + __TypeKind::NON_NULL => { + r = rf.of_type.as_ref().map(|t| t.clone()).map(|t| *t); + continue; } __TypeKind::Other(_) => { - r = rf.of_type.as_ref().map(|t| t.clone()).map(|t| *t) + r = rf.of_type.as_ref().map(|t| t.clone()).map(|t| *t); + continue; } - _ => {} + __TypeKind::INTERFACE => break, + __TypeKind::UNION => break, }, None => break, }, None => break, - } + }; } + println!("rep: {}", representation); + println!("{:?}", t); + representation } } @@ -124,3 +130,222 @@ impl From<&TypeRef> for Scalar { } } } + +pub fn get_type_from_name<'t>(types: &'t [FullType], name: &'t str) -> Option<&'t FullType> { + types + .into_iter() + .find(|t| t.name.as_ref().map(|s| s.as_str()) == Some(name)) +} + +pub fn type_ref_is_optional(type_ref: &TypeRef) -> bool { + type_ref + .kind + .pipe(|k| *k != __TypeKind::NON_NULL) + .unwrap_or(false) +} + +pub fn type_ref_is_scalar(type_ref: &TypeRef) -> bool { + type_ref + .kind + .pipe(|k| *k == __TypeKind::SCALAR) + .unwrap_or(false) +} + +pub fn type_ref_is_object(type_ref: &TypeRef) -> bool { + type_ref + .kind + .pipe(|k| *k == __TypeKind::OBJECT) + .unwrap_or(false) +} + +pub fn type_ref_is_list(type_ref: &TypeRef) -> bool { + type_ref + .kind + .pipe(|k| *k == __TypeKind::LIST) + .unwrap_or(false) +} + +pub fn input_values_has_optionals(input_values: &[InputValue]) -> bool { + input_values + .into_iter() + .map(|k| type_ref_is_optional(&k.type_)) + .filter(|k| *k) + .collect::>() + .len() + > 0 +} + +pub fn input_values_is_empty(input_values: &[InputValue]) -> bool { + input_values.len() > 0 +} + +#[cfg(test)] +mod test { + use dagger_core::introspection::{FullType, InputValue, TypeRef, __TypeKind}; + use pretty_assertions::assert_eq; + + use crate::functions::{input_values_has_optionals, type_ref_is_optional}; + + use super::get_type_from_name; + + #[test] + fn get_type_from_name_has_no_item() { + let input = vec![]; + let output = get_type_from_name(&input, "some-name"); + + assert_eq!(output.is_none(), true); + } + + #[test] + fn get_type_from_name_has_item() { + let name = "some-name"; + let input = vec![FullType { + kind: None, + name: Some(name.to_string()), + description: None, + fields: None, + input_fields: None, + interfaces: None, + enum_values: None, + possible_types: None, + }]; + let output = get_type_from_name(&input, name); + + assert_eq!(output.is_some(), true); + } + + #[test] + fn get_type_from_name_has_item_multiple_entries() { + let name = "some-name"; + let input = vec![ + FullType { + kind: None, + name: Some(name.to_string()), + description: None, + fields: None, + input_fields: None, + interfaces: None, + enum_values: None, + possible_types: None, + }, + FullType { + kind: None, + name: Some(name.to_string()), + description: None, + fields: None, + input_fields: None, + interfaces: None, + enum_values: None, + possible_types: None, + }, + ]; + let output = get_type_from_name(&input, name); + + assert_eq!(output.is_some(), true); + } + + #[test] + fn type_ref_is_optional_has_none() { + let input = TypeRef { + kind: None, + name: None, + of_type: None, + }; + let output = type_ref_is_optional(&input); + + assert_eq!(output, false); + } + + #[test] + fn type_ref_is_optional_is_required() { + let input = TypeRef { + kind: Some(__TypeKind::NON_NULL), + name: None, + of_type: None, + }; + let output = type_ref_is_optional(&input); + + assert_eq!(output, false); + } + + #[test] + fn type_ref_is_optional_is_optional() { + let input = TypeRef { + kind: Some(__TypeKind::OBJECT), + name: None, + of_type: None, + }; + let output = type_ref_is_optional(&input); + + assert_eq!(output, true); + } + + #[test] + fn input_values_has_optionals_none() { + let input = vec![]; + + let output = input_values_has_optionals(&input); + + assert_eq!(output, false); + } + + #[test] + fn input_values_has_optionals_has_optional() { + let input = vec![ + InputValue { + name: "some-name".to_string(), + description: None, + type_: TypeRef { + kind: Some(__TypeKind::NON_NULL), + name: None, + of_type: None, + }, + default_value: None, + }, + InputValue { + name: "some-other-name".to_string(), + description: None, + type_: TypeRef { + kind: Some(__TypeKind::OBJECT), + name: None, + of_type: None, + }, + default_value: None, + }, + ]; + + let output = input_values_has_optionals(&input); + + assert_eq!(output, true); + } + + #[test] + fn input_values_has_optionals_is_required() { + let input = vec![ + InputValue { + name: "some-name".to_string(), + description: None, + type_: TypeRef { + kind: Some(__TypeKind::NON_NULL), + name: None, + of_type: None, + }, + default_value: None, + }, + InputValue { + name: "some-other-name".to_string(), + description: None, + type_: TypeRef { + kind: Some(__TypeKind::NON_NULL), + name: None, + of_type: None, + }, + default_value: None, + }, + ]; + + let output = input_values_has_optionals(&input); + + assert_eq!(output, false); + } +} diff --git a/crates/dagger-codegen/src/lib.rs b/crates/dagger-codegen/src/lib.rs index c03339e..8e4ca7b 100644 --- a/crates/dagger-codegen/src/lib.rs +++ b/crates/dagger-codegen/src/lib.rs @@ -1,6 +1,7 @@ mod functions; mod generator; pub mod rust; +pub mod utility; mod visitor; use dagger_core::introspection::Schema; diff --git a/crates/dagger-codegen/src/rust/mod.rs b/crates/dagger-codegen/src/rust/mod.rs index 5e52c1b..eb6717c 100644 --- a/crates/dagger-codegen/src/rust/mod.rs +++ b/crates/dagger-codegen/src/rust/mod.rs @@ -8,9 +8,11 @@ use dagger_core::introspection::Schema; use eyre::Context; use genco::prelude::rust; +use crate::functions::CommonFunctions; use crate::generator::Generator; use crate::visitor::{VisitHandlers, Visitor}; +use self::format::FormatTypeFunc; use self::templates::enum_tmpl::render_enum; use self::templates::input_tmpl::render_input; use self::templates::object_tmpl::render_object; @@ -21,6 +23,8 @@ pub struct RustGenerator {} impl Generator for RustGenerator { fn generate(&self, schema: Schema) -> eyre::Result { let render = Arc::new(Mutex::new(rust::Tokens::new())); + let common_funcs = CommonFunctions::new(Arc::new(FormatTypeFunc {})); + println!("generating dagger for rust"); let visitor = Visitor { schema, @@ -28,6 +32,7 @@ impl Generator for RustGenerator { visit_scalar: Arc::new({ let render = render.clone(); move |t| { + println!("generating scalar"); let rendered_scalar = render_scalar(t)?; let mut render = render.lock().unwrap(); @@ -35,6 +40,8 @@ impl Generator for RustGenerator { render.append(rendered_scalar); render.push(); + println!("generated scalar"); + Ok(()) } }), @@ -42,12 +49,14 @@ impl Generator for RustGenerator { let render = render.clone(); move |t| { + println!("generating object"); let rendered_scalar = render_object(t)?; let mut render = render.lock().unwrap(); render.append(rendered_scalar); render.push(); + println!("generated object"); Ok(()) } @@ -56,12 +65,14 @@ impl Generator for RustGenerator { let render = render.clone(); move |t| { - let rendered_scalar = render_input(t)?; + println!("generating input"); + let rendered_scalar = render_input(&common_funcs, t)?; let mut render = render.lock().unwrap(); render.append(rendered_scalar); render.push(); + println!("generated input"); Ok(()) } @@ -70,12 +81,14 @@ impl Generator for RustGenerator { let render = render.clone(); move |t| { + println!("generating enum"); let rendered_scalar = render_enum(t)?; let mut render = render.lock().unwrap(); render.append(rendered_scalar); render.push(); + println!("generated enum"); Ok(()) } @@ -85,6 +98,8 @@ impl Generator for RustGenerator { visitor.run()?; + println!("done generating objects"); + let rendered = render.lock().unwrap(); rendered diff --git a/crates/dagger-codegen/src/rust/templates/input_tmpl.rs b/crates/dagger-codegen/src/rust/templates/input_tmpl.rs index 1e029f1..48c1dc0 100644 --- a/crates/dagger-codegen/src/rust/templates/input_tmpl.rs +++ b/crates/dagger-codegen/src/rust/templates/input_tmpl.rs @@ -1,13 +1,35 @@ -use dagger_core::introspection::FullType; +use dagger_core::introspection::{FullType, FullTypeInputFields}; use genco::prelude::rust; use genco::quote; +use crate::functions::CommonFunctions; use crate::rust::functions::format_name; -pub fn render_input(t: &FullType) -> eyre::Result { +pub fn render_input(funcs: &CommonFunctions, t: &FullType) -> eyre::Result { Ok(quote! { pub struct $(format_name(t.name.as_ref().unwrap())) { - + $(render_input_fields(funcs, t.input_fields.as_ref().unwrap_or(&Vec::new()) )) } }) } + +pub fn render_input_fields( + funcs: &CommonFunctions, + fields: &[FullTypeInputFields], +) -> Option { + let rendered_fields = fields.iter().map(|f| render_input_field(funcs, f)); + + if rendered_fields.len() == 0 { + None + } else { + Some(quote! { + $(for field in rendered_fields join ($['\r']) => $field) + }) + } +} + +pub fn render_input_field(funcs: &CommonFunctions, field: &FullTypeInputFields) -> rust::Tokens { + quote! { + $(&field.input_value.name): $(funcs.format_input_type(&field.input_value.type_)) + } +} diff --git a/crates/dagger-codegen/src/rust/templates/object_tmpl.rs b/crates/dagger-codegen/src/rust/templates/object_tmpl.rs index 6a82058..8653c78 100644 --- a/crates/dagger-codegen/src/rust/templates/object_tmpl.rs +++ b/crates/dagger-codegen/src/rust/templates/object_tmpl.rs @@ -1,12 +1,40 @@ -use dagger_core::introspection::FullType; +use dagger_core::introspection::{FullType, FullTypeFields}; use genco::prelude::rust; use genco::quote; use crate::rust::functions::format_name; +use crate::utility::OptionExt; pub fn render_object(t: &FullType) -> eyre::Result { Ok(quote! { - pub struct $(format_name(t.name.as_ref().unwrap())) { + pub struct $(t.name.pipe(|s| format_name(s))) { + + } + + $(t.fields.pipe(render_optional_args)) + + impl $(t.name.pipe(|s| format_name(s))) { + } }) } + +fn render_optional_args(fields: &Vec) -> Option { + let rendered_fields = fields + .iter() + .map(render_optional_arg) + .flatten() + .collect::>(); + + if rendered_fields.len() == 0 { + None + } else { + Some(quote! { + $(for field in rendered_fields join ($['\r']) => $field) + }) + } +} + +fn render_optional_arg(field: &FullTypeFields) -> Option { + todo!() +} diff --git a/crates/dagger-codegen/src/utility.rs b/crates/dagger-codegen/src/utility.rs new file mode 100644 index 0000000..11594e5 --- /dev/null +++ b/crates/dagger-codegen/src/utility.rs @@ -0,0 +1,18 @@ +pub trait OptionExt<'t, T: 't> { + fn pipe(&'t self, f: F) -> Option + where + F: FnOnce(&'t T) -> U; +} + +impl<'t, T: 't> OptionExt<'t, T> for Option { + #[inline] + fn pipe(&'t self, f: F) -> Option + where + F: FnOnce(&'t T) -> U, + { + match *self { + Some(ref x) => Some(f(x)), + None => None, + } + } +}