Skip to content

Commit

Permalink
add suggested changes
Browse files Browse the repository at this point in the history
* Doc comment changes
* rename from `name` to `target_kind_name` for template variable
* Update Result to use `IonSchemaError` instead of `IonError`
* Add newline at the end of each template
* Other variable renaming changes
  • Loading branch information
desaikd committed Dec 7, 2023
1 parent f17039c commit cb81097
Show file tree
Hide file tree
Showing 11 changed files with 61 additions and 39 deletions.
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ ion-schema = "0.10.0"
serde = { version = "1.0.163", features = ["derive"] }
serde_json = { version = "1.0.81", features = [ "arbitrary_precision", "preserve_order" ] }
base64 = "0.21.1"
tera = "1.18.1"
convert_case = "0.6.0"
tera = { version = "1.18.1", optional = true }
convert_case = { version = "0.6.0", optional = true }
matches = "0.1.10"
thiserror = "1.0.50"

Expand All @@ -33,8 +33,8 @@ assert_cmd = "~1.0.5"
tempfile = "~3.5.0"

[features]
deafault = []
beta-subcommands = []
default = []
beta-subcommands = ["dep:tera", "dep:convert_case"]

[[bin]]
name = "ion"
Expand Down
6 changes: 4 additions & 2 deletions src/bin/ion/commands/beta/generate/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ impl CodeGenContext {
/// Represents a data model type that can be used to determine which templates can be used for code generation.
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum DataModel {
Value, // a struct with a scalar value (used for `type` constraint)
Sequence, // a struct with a sequence value (used for `element` constraint)
Value, // a struct with a scalar value (used for `type` constraint)
// TODO: Make Sequence parameterized over data type.
// add a data type for sequence here that can be used to read elements for that data type.
Sequence, // a struct with a sequence/collection value (used for `element` constraint)
Struct,
}

Expand Down
48 changes: 33 additions & 15 deletions src/bin/ion/commands/beta/generate/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::io::Write;
use std::path::Path;
use tera::{Context, Tera};

// TODO: generator cna store language and output path as it doesn't change during code generation process
// TODO: generator can store language and output path as it doesn't change during code generation process
pub(crate) struct CodeGenerator<'a> {
// Represents the templating engine - tera
// more information: https://docs.rs/tera/latest/tera/
Expand Down Expand Up @@ -67,7 +67,7 @@ impl<'a> CodeGenerator<'a> {

/// Generates code for given Ion Schema
pub fn generate(&mut self, schema: IslSchema) -> CodeGenResult<()> {
// this will be used for Rust to create mod.rs which lists all the generates modules
// this will be used for Rust to create mod.rs which lists all the generated modules
let mut modules = vec![];
let mut module_context = tera::Context::new();

Expand Down Expand Up @@ -107,7 +107,10 @@ impl<'a> CodeGenerator<'a> {
let mut code_gen_context = CodeGenContext::new();

// Set the target kind name of the data model (i.e. enum/class)
context.insert("name", &data_model_name.to_case(Case::UpperCamel));
context.insert(
"target_kind_name",
&data_model_name.to_case(Case::UpperCamel),
);

let constraints = isl_type.constraints();
for constraint in constraints {
Expand Down Expand Up @@ -197,6 +200,21 @@ impl<'a> CodeGenerator<'a> {
}

/// Verify that the current data model is same as previously determined data model
/// This is referring to data model determined with each constraint that is verifies
/// that all the constraints map to a single data model and not different data models.
/// e.g.
/// ```
/// type::{
/// name: foo,
/// type: string,
/// fields:{
/// source: String,
/// destination: String
/// }
/// }
/// ```
/// For the above schema, both `fields` and `type` constraints map to different data models
/// respectively Struct(with given fields `source` and `destination`) and Value(with a single field that has String data type).
fn verify_data_model_consistency(
&mut self,
current_data_model: DataModel,
Expand Down Expand Up @@ -274,7 +292,7 @@ impl<'a> CodeGenerator<'a> {
})
}

/// Generates field value in a struct which represents a sequence data type in codegen's programming language
/// Generates an appropriately typed sequence in the target programming language to use as a field value
pub fn generate_sequence_field_value(
&mut self,
name: String,
Expand All @@ -293,16 +311,16 @@ impl<'a> CodeGenerator<'a> {
name
}

/// Generates read API for a data model
/// This adds statements for reading Ion value based on given data model that will be used by data model templates
/// Generates Generates a read API for an abstract data type.
/// This adds statements for reading each the Ion value(s) that collectively represent the given abstract data type.
// TODO: add support for Java
fn generate_read_api(
&mut self,
context: &mut Context,
tera_fields: &mut Vec<Field>,
code_gen_context: &mut CodeGenContext,
) -> CodeGenResult<()> {
let mut statements = vec![];
let mut read_statements = vec![];

if code_gen_context.data_model == Some(DataModel::Struct)
|| code_gen_context.data_model == Some(DataModel::Value)
Expand All @@ -320,11 +338,11 @@ impl<'a> CodeGenerator<'a> {
for tera_field in tera_fields {
if !self.is_built_in_type(&tera_field.value) {
if code_gen_context.data_model == Some(DataModel::Sequence) {
statements.push(format!(
read_statements.push(format!(
"\"{}\" => {{ data_model.{} =",
&tera_field.name, &tera_field.name,
));
statements.push(
read_statements.push(
r#"{
let mut values = vec![];
reader.step_in()?;
Expand All @@ -333,18 +351,18 @@ impl<'a> CodeGenerator<'a> {
);
let sequence_type = &tera_field.value.replace("Vec<", "").replace('>', "");
if !self.is_built_in_type(sequence_type) {
statements.push(format!(
read_statements.push(format!(
"values.push({}::read_from(reader)?)",
sequence_type
));
} else {
statements.push(format!(
read_statements.push(format!(
"values.push(reader.read_{}()?)",
sequence_type.to_lowercase()
));
}

statements.push(
read_statements.push(
r#"}
values }}"#
.to_string(),
Expand All @@ -355,7 +373,7 @@ impl<'a> CodeGenerator<'a> {
&format!("{}::read_from(reader)?", &tera_field.value,),
);
} else {
statements.push(format!(
read_statements.push(format!(
"\"{}\" => {{ data_model.{} = {}::read_from(reader)?;}}",
&tera_field.name, &tera_field.name, &tera_field.value,
));
Expand All @@ -367,7 +385,7 @@ impl<'a> CodeGenerator<'a> {
&format!("reader.read_{}()?", &tera_field.value.to_lowercase(),),
);
}
statements.push(format!(
read_statements.push(format!(
"\"{}\" => {{ data_model.{} = reader.read_{}()?;}}",
&tera_field.name,
&tera_field.name,
Expand All @@ -376,7 +394,7 @@ impl<'a> CodeGenerator<'a> {
}
}
}
context.insert("statements", &statements);
context.insert("statements", &read_statements);
Ok(())
}

Expand Down
4 changes: 1 addition & 3 deletions src/bin/ion/commands/beta/generate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,7 @@ impl IonCliCommand for GenerateCommand {
println!("Started generating code...");

// generate code based on schema and programming language
CodeGenerator::new(language, output)
.generate(schema)
.unwrap();
CodeGenerator::new(language, output).generate(schema)?;

println!("Code generation complete successfully!");
println!("Path to generated code: {}", output.display());
Expand Down
2 changes: 1 addition & 1 deletion src/bin/ion/commands/beta/generate/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub type CodeGenResult<T> = Result<T, CodeGenError>;
#[derive(Debug, Error)]
pub enum CodeGenError {
#[error("{source:?}")]
IonError {
IonSchemaError {
#[from]
source: IonSchemaError,
},
Expand Down
6 changes: 3 additions & 3 deletions src/bin/ion/commands/beta/generate/templates/java/class.templ
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{% if import %}
import ion_data_model.{{ import_type }};
{% endif %}
public final class {{ name }} {
public final class {{ target_kind_name }} {
{% for field in fields -%}
private final {{ field.value }} {{ field.name }};
{% endfor %}

public {{ name }}({% for field in fields -%}{{ field.value }} {{ field.name }},{% endfor %}) {
public {{ target_kind_name }}({% for field in fields -%}{{ field.value }} {{ field.name }},{% endfor %}) {
{% for field in fields -%}
this.{{ field.name }} = {{ field.name }};
{% endfor %}
Expand All @@ -16,4 +16,4 @@ public final class {{ name }} {
return this.{{ field.name }};
}
{% endfor %}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{% for module in modules -%}
pub mod {{ module }};
{% endfor %}
{% endfor %}
10 changes: 5 additions & 5 deletions src/bin/ion/commands/beta/generate/templates/rust/struct.templ
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ use crate::ion_data_model::{{ import.module_name }}::{{ import.type_name }};
{% endfor %}

#[derive(Debug, Clone, Default)]
pub struct {{ name }} {
pub struct {{ target_kind_name }} {
{% for field in fields -%}
{{ field.name | indent(first = true) }}: {{ field.value }},
{% endfor %}
}

impl {{ name }} {
impl {{ target_kind_name }} {
pub fn new({% for field in fields -%}{{ field.name }}: {{ field.value }},{% endfor %}) -> Self {
Self {
{% for field in fields -%}
Expand All @@ -29,11 +29,11 @@ impl {{ name }} {
pub fn read_from(reader: &mut Reader) -> IonResult<Self> {
reader.next()?;
{% if data_model == "UnitStruct"%}
let mut data_model = {{ name }}::default();
let mut data_model = {{ target_kind_name }}::default();
data_model.value = {{ read_statement }};
{% else %}
{% if data_model == "Struct"%}reader.step_in()?;{% endif %}
let mut data_model = {{ name }}::default();
let mut data_model = {{ target_kind_name }}::default();
while reader.next()? != StreamItem::Nothing {
if let Some(field_name) = reader.field_name()?.text() {
match field_name {
Expand All @@ -57,4 +57,4 @@ impl {{ name }} {
{% endfor %}
Ok(())
}
}
}
2 changes: 1 addition & 1 deletion src/bin/ion/commands/beta/generate/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ impl IonSchemaType {
(Int, Java) => "int",
(String | Symbol, _) => "String",
(Float, Rust) => "f64",
(Float, Java) => "float",
(Float, Java) => "double",
(Bool, Rust) => "bool",
(Bool, Java) => "boolean",
(Blob | Clob, Rust) => "Vec<u8>",
Expand Down
4 changes: 4 additions & 0 deletions src/bin/ion/commands/beta/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pub mod count;
pub mod from;

#[cfg(feature = "beta-subcommands")]
pub mod generate;
pub mod head;
pub mod inspect;
Expand All @@ -10,6 +12,7 @@ pub mod to;

use crate::commands::beta::count::CountCommand;
use crate::commands::beta::from::FromNamespace;
#[cfg(feature = "beta-subcommands")]
use crate::commands::beta::generate::GenerateCommand;
use crate::commands::beta::head::HeadCommand;
use crate::commands::beta::inspect::InspectCommand;
Expand Down Expand Up @@ -40,6 +43,7 @@ impl IonCliCommand for BetaNamespace {
Box::new(FromNamespace),
Box::new(ToNamespace),
Box::new(SymtabNamespace),
#[cfg(feature = "beta-subcommands")]
Box::new(GenerateCommand),
]
}
Expand Down
8 changes: 4 additions & 4 deletions tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,10 @@ fn test_write_all_values(#[case] number: i32, #[case] expected_output: &str) ->
&["pub fn name(&self) -> &String {", "pub fn id(&self) -> &i64 {"]
)]
#[case(
"unit_struct",
"value_struct",
r#"
type::{
name: unit_struct,
name: value_struct,
type: int // this will be a field in struct
}
"#,
Expand Down Expand Up @@ -323,10 +323,10 @@ fn test_code_generation_in_rust(
&["public String getName() {", "public int getId() {"]
)]
#[case(
"UnitStruct",
"ValueStruct",
r#"
type::{
name: unit_struct,
name: value_struct,
type: int // this will be a field in struct
}
"#,
Expand Down

0 comments on commit cb81097

Please sign in to comment.