Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Support Vecs #19

Merged
merged 9 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,20 @@ jobs:
- instructor
steps:
- uses: actions/checkout@v4
- name: Cache cargo-nextest
id: cargo-nextest-cache
uses: actions/cache@v3
with:
path: ~/.cargo/bin/cargo-nextest
key: ${{ runner.os }}-cargo-nextest-${{ matrix.toolchain }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-nextest-${{ matrix.toolchain }}-
${{ runner.os }}-cargo-nextest-
- name: Install cargo-nextest
if: steps.cargo-nextest-cache.outputs.cache-hit != 'true'
run: cargo install cargo-nextest --locked
- run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
- run: cd ${{ matrix.crate }} && cargo build --verbose
- run: cd ${{ matrix.crate }} && cargo test --verbose
- run: cd ${{ matrix.crate }} && cargo nextest run --verbose --retries 3
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
25 changes: 25 additions & 0 deletions instruct-macros-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ impl InstructMacroResult {
}
}
}

pub fn set_list(self, is_list: bool) -> InstructMacroResult {
match self {
InstructMacroResult::Struct(struct_info) => {
InstructMacroResult::Struct(struct_info.set_list(is_list))
}
InstructMacroResult::Enum(enum_info) => {
InstructMacroResult::Enum(enum_info.set_list(is_list))
}
}
}
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
Expand All @@ -48,6 +59,7 @@ pub struct StructInfo {
pub description: String,
pub parameters: Vec<Parameter>,
pub is_optional: bool,
pub is_list: bool,
}

impl StructInfo {
Expand All @@ -67,6 +79,11 @@ impl StructInfo {
self.is_optional = is_optional;
self
}

pub fn set_list(mut self, is_list: bool) -> StructInfo {
self.is_list = is_list;
self
}
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
Expand All @@ -82,6 +99,7 @@ pub struct ParameterInfo {
pub r#type: String,
pub comment: String,
pub is_optional: bool,
pub is_list: bool,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
Expand All @@ -91,6 +109,7 @@ pub struct EnumInfo {
pub r#type: String,
pub description: String,
pub is_optional: bool,
pub is_list: bool,
}

impl EnumInfo {
Expand All @@ -110,6 +129,11 @@ impl EnumInfo {
self.is_optional = is_optional;
self
}

pub fn set_list(mut self, is_list: bool) -> EnumInfo {
self.is_list = is_list;
self
}
}

pub struct FieldInfo {
Expand All @@ -118,4 +142,5 @@ pub struct FieldInfo {
pub r#type: String,
pub is_complex: bool,
pub is_optional: bool,
pub is_list: bool,
}
43 changes: 40 additions & 3 deletions instruct-macros/src/helpers/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ pub fn extract_parameter_information(fields: &syn::FieldsNamed) -> Vec<FieldInfo
let field_type = &field.ty;
let serialized_field_type = quote!(#field_type).to_string();

let serialized_field_type = if serialized_field_type.contains("Option <") {
let serialized_field_type = if serialized_field_type.contains("Option <")
|| serialized_field_type.contains("Vec <")
{
serialized_field_type.replace(" ", "")
} else {
serialized_field_type
Expand All @@ -46,11 +48,16 @@ pub fn extract_parameter_information(fields: &syn::FieldsNamed) -> Vec<FieldInfo
r#type: serialized_field_type.clone(),
is_complex: is_complex_type(serialized_field_type.clone()),
is_optional: is_option_type(&serialized_field_type),
is_list: is_list_type(serialized_field_type.clone()),
}
})
.collect()
}

fn is_list_type(field_type: String) -> bool {
field_type.starts_with("Vec<") && field_type.ends_with(">")
}

pub fn is_complex_type(field_type: String) -> bool {
let simple_types = vec![
"bool", "char", "f32", "f64", "i8", "i16", "i32", "i64", "i128", "isize", "str", "String",
Expand All @@ -62,6 +69,11 @@ pub fn is_complex_type(field_type: String) -> bool {
.map(|&t| format!("Option<{}>", t))
.collect();

let vec_types: Vec<String> = simple_types
.iter()
.map(|&t| format!("Vec<{}>", t))
.collect();

if simple_types.contains(&field_type.as_str()) {
return false;
}
Expand All @@ -70,6 +82,10 @@ pub fn is_complex_type(field_type: String) -> bool {
return false;
}

if vec_types.contains(&field_type) {
return false;
}

true
}

Expand All @@ -93,14 +109,25 @@ pub fn extract_parameters(fields: &syn::FieldsNamed) -> Vec<proc_macro2::TokenSt
let field_type = &field.r#type;
let field_comment = &field.description;
let is_option = is_option_type(field_type);
let is_list = field.is_list;



if !field.is_complex {

let field_type = if is_list {
extract_nested_type(&field_type[4..field_type.len() - 1])
} else {
field_type.to_string()
};

quote! {
parameters.push(Parameter::Field(ParameterInfo {
name: #field_name.to_string(),
r#type: #field_type.to_string(),
comment: #field_comment.to_string(),
is_optional: #is_option,
is_list: #is_list,
}));
}
} else if is_option_type(field_type) {
Expand All @@ -111,10 +138,20 @@ pub fn extract_parameters(fields: &syn::FieldsNamed) -> Vec<proc_macro2::TokenSt
parameters.push(#field_type::get_info().override_description(#field_comment.to_string()).set_optional(#is_option).wrap_info(#field_name.to_string()));
}
} else {
let field_type = Ident::new(&field_type, proc_macro2::Span::call_site()); // Convert string to an identifier
let is_list = field.is_list;


let field_type = if is_list {
extract_nested_type(&field_type[4..field_type.len() - 1])
} else {
field_type.to_string()
};

let field_type = Ident::new(&field_type, proc_macro2::Span::call_site()); // Convert string to an identifier


quote! {
parameters.push(#field_type::get_info().override_description(#field_comment.to_string()).set_optional(#is_option).wrap_info(#field_name.to_string()));
parameters.push(#field_type::get_info().override_description(#field_comment.to_string()).set_optional(#is_option).set_list(#is_list).wrap_info(#field_name.to_string()));
}
}
})
Expand Down
6 changes: 4 additions & 2 deletions instruct-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ fn generate_instruct_macro_enum(input: &DeriveInput) -> proc_macro2::TokenStream
r#enum: vec![#(#enum_variants.to_string()),*],
r#type: stringify!(#name).to_string(),
description: #description.to_string(),
is_optional:false
is_optional:false,
is_list: false
})
};

Expand Down Expand Up @@ -122,7 +123,8 @@ fn generate_instruct_macro_struct(input: &DeriveInput) -> proc_macro2::TokenStre
name: stringify!(#name).to_string(),
description: #description.to_string(),
parameters,
is_optional:false
is_optional:false,
is_list: false,
})
}

Expand Down
13 changes: 13 additions & 0 deletions instruct-macros/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,18 @@ mod tests {
r#type: "String".to_string(),
comment: "This is a sample example that spans across three lines".to_string(),
is_optional: false,
is_list: false,
}),
Parameter::Field(ParameterInfo {
name: "field2".to_string(),
r#type: "str".to_string(),
comment: "This is a test field".to_string(),
is_optional: false,
is_list: false,
}),
],
is_optional: false,
is_list: false,
};

let info_struct = match info {
Expand Down Expand Up @@ -121,12 +124,14 @@ mod tests {
r#type: "String".to_string(),
comment: "".to_string(),
is_optional: false,
is_list: false,
}),
Parameter::Field(ParameterInfo {
name: "age".to_string(),
r#type: "u8".to_string(),
comment: "".to_string(),
is_optional: false,
is_list: false,
}),
Parameter::Struct(StructInfo {
name: "address".to_string(),
Expand All @@ -137,18 +142,22 @@ mod tests {
r#type: "String".to_string(),
comment: "".to_string(),
is_optional: false,
is_list: false,
}),
Parameter::Field(ParameterInfo {
name: "city".to_string(),
r#type: "String".to_string(),
comment: "".to_string(),
is_optional: false,
is_list: false,
}),
],
is_optional: false,
is_list: false,
}),
],
is_optional: false,
is_list: false,
};

let info_struct = match info {
Expand Down Expand Up @@ -181,6 +190,7 @@ mod tests {
r#type: "Status".to_string(),
description: "".to_string(),
is_optional: false,
is_list: false,
};

let info_enum = match info {
Expand Down Expand Up @@ -220,6 +230,7 @@ mod tests {
r#type: "String".to_string(),
comment: "".to_string(),
is_optional: false,
is_list: false,
}),
Parameter::Enum(EnumInfo {
title: "status".to_string(),
Expand All @@ -231,9 +242,11 @@ mod tests {
r#type: "Status".to_string(),
description: "This is an enum representing the status of a person".to_string(),
is_optional: false,
is_list: false,
}),
],
is_optional: false,
is_list: false,
};

let info_struct = match info {
Expand Down
7 changes: 7 additions & 0 deletions instruct-macros/tests/test_option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,21 @@ mod tests {
name: "TestOptionStruct".to_string(),
description: "This is a struct with Option types".to_string(),
is_optional: false,
is_list: false,
parameters: vec![
Parameter::Field(ParameterInfo {
name: "field1".to_string(),
r#type: "Option<String>".to_string(),
comment: "This is an optional string field".to_string(),
is_optional: true,
is_list: false,
}),
Parameter::Field(ParameterInfo {
name: "field2".to_string(),
r#type: "Option<i32>".to_string(),
comment: "This is an optional integer field".to_string(),
is_optional: true,
is_list: false,
}),
],
};
Expand Down Expand Up @@ -83,17 +86,21 @@ mod tests {
r#type: "String".to_string(),
comment: "This is the user's name".to_string(),
is_optional: false,
is_list: false,
}),
Parameter::Field(ParameterInfo {
name: "age".to_string(),
r#type: "i32".to_string(),
comment: "This is the user's age".to_string(),
is_optional: false,
is_list: false,
}),
],
is_optional: true,
is_list: false,
})],
is_optional: false,
is_list: false,
};

let info_struct = match info {
Expand Down
Loading
Loading