SlideShare a Scribd company logo
1 of 30
Download to read offline
The wages of syn is ...
by @jayvdb
John Mark Vandenberg
Chapter 10
https://www.google.com.au/books/edition/The_Communion_of_Saincts_A_Treatise_of_t/fR9lAAAAcAAJ
Romans 6:23
https://biblehub.com/interlinear/romans/6-23.htm
Romans 6:23
●
Syn:
Romans 6:23
●
Syn:
Romans 6:23
●
ſyn?
Romans 6:23
●
ſyn?
Romans 6:23
●
ſyn?
Romans 6:23
●
ſyn?
Romans 6:23 Rust crates.io
Romans 6:23 Rust crates.io
Java, with mustache templates,
with JavaScript CLI wrapper, and
does not support adding custom
“derive” to the structs, or easily
using custom templates
openapi-generator
Rust, but only supports OpenAPI
v2. Downgrading v3 to v2 is lossy,
but acceptable for models-only.
A small python script used to
downgrade.
No templating for custom derive.
paperclip
Rust, OpenAPI v3, YAML, Jinja
templates.
Builds, works well, but the
templates are not as good as
progenitor.
schema-tools
Rust, OpenAPI v3, no YAML.
Two pulls requests and we’re
100% Rust, OpenAPI v3, YAML.
Custom derive require hacks.
progenitor
01
01
02
02
03
03
04
04
Java, with mustache templates,
with JavaScript CLI wrapper, and
does not support adding custom
“derive” to the structs, or easily
using custom templates
openapi-generator
Rust, but only supports OpenAPI
v2. Downgrading v3 to v2 is lossy,
but acceptable for models-only.
A small python script used to
downgrade.
No templating for custom derive.
paperclip
Rust, OpenAPI v3, YAML, Jinja
templates.
Builds, works well, but refuses to
install.
schema-tools
Rust, OpenAPI v3, no YAML.
Two pulls requests and we’re
100% Rust, OpenAPI v3, YAML.
Custom derive require hacks.
progenitor
01
01
02
02
03
03
04
04
What is Progenitor?
Progenitor is a Rust crate for generating opinionated
clients from API descriptions in the OpenAPI 3.0.x
specification. It makes use of Rust futures for async API
calls and Streams for paginated interfaces.
It generates a type called Client with methods that
correspond to the operations specified in the OpenAPI
document.
Why use Progenitor?
OpenAPI between services:
* Standards based
* Keeps use honest
* Free code
Progenitor before syn – forking hell
Progenitor before syn – forking hell
Progenitor before syn – forking hell
Progenitor before syn – forking hell
Progenitor before syn – forking hell
Progenitor before syn – forking hell
Progenitor before syn – forking hell
fn main() {
let mut project_root = lets_find_up::find_up("Makefile.toml").unwrap().unwrap();
project_root.pop(); // Drop filename from path
let input_yaml = format!("{}/openapi.yaml", project_root.display());
let spec = load_spec(input_yaml);
// The use of `with_patch` here is to provide similar behaviour to
// unmerged https://github.com/oxidecomputer/typify/pull/184
let mut schema_names: ;
for schema_name in schema_names.iter().cloned() {
if !is_pascal_case(&schema_name) {
panic!("{schema_name} is not pascal case which will cause bugs.");
}
let mut patch = progenitor_impl::TypePatch::default();
// The enums have a Default impl added by typify
if !schema_name.ends_with("Enum")
// MySpecialEnum has a custom Default impl added in elsewhere.
&& schema_name != "MySpecialEnum"
{
patch.with_derive("Default");
}
if !TABLE_SCHEMAS.contains(&schema_name.as_str()) {
patch.with_derive("FieldType");
}
settings.with_patch(schema_name, &patch);
}
let input = generate_rust(&spec, &settings);
Progenitor after syn – lib-erty
...
fn main() {
let input = generate_rust(&spec, &settings);
let modified = transform_rust(input);
let out_filename = format!("{}/rust/models/src/lib.rs", project_root.display());
write_rust(out_filename, &modified);
}
Progenitor after syn – lib-erty
...
fn generate_rust(
spec: &OpenAPI,
settings: &progenitor_impl::GenerationSettings
) -> syn::File {
let mut generator = progenitor_impl::Generator::new(settings);
let original_tokens = generator.generate_tokens(spec).unwrap();
let ast: syn::File = syn::parse2(original_tokens).unwrap();
ast
}
Progenitor after syn – lib-erty
fn transform_rust(input: syn::File) -> syn::File {
let extra_butane_use: syn::Stmt = parse_quote! {
use butane::{
butane_type, model, ButaneJson, DataObject, FieldType, ForeignKey,
FromSql, Many, SqlType, SqlVal, SqlValRef, ToSql,
};
};
let extra_fake_use: syn::Stmt = parse_quote! {
use fake::{Dummy, Fake};
};
let extra_rand_use: syn::Stmt = parse_quote! {
use rand;
};
let use_butane_item: &syn::Item = cast!(&extra_butane_use, syn::Stmt::Item);
let use_fake_item: &syn::Item = cast!(&extra_fake_use, syn::Stmt::Item);
let use_rand_item: &syn::Item = cast!(&extra_rand_use, syn::Stmt::Item);
// Only the 'pub mod types { .. }' item from the input is wanted.
// i.e. remove the reqwest client
const MOD_TYPES_INDEX: usize = 3;
let mut mod_types: syn::ItemMod = cast!(&input.items[MOD_TYPES_INDEX], syn::Item::Mod).clone();
let (brace, mod_types_items) = mod_types.content.clone().unwrap();
let mut new_mod_types_items: Vec<syn::Item> = vec![];
new_mod_types_items.push(use_butane_item.clone());
new_mod_types_items.push(use_fake_item.clone());
new_mod_types_items.push(use_rand_item.clone());
for item in mod_types_items {
match item.clone() {
syn::Item::Struct(s) => {
let ident_name = s.ident.to_string();
if TABLE_SCHEMAS.contains(&ident_name.as_str()) {
// This branch is for the tables
let new_struct = transform_table(ident_name, s);
new_mod_types_items.push(syn::Item::Struct(new_struct));
} else {
// Serialise non-table schemas as JSON
let attribute: syn::Attribute = parse_quote! {
#[butane_type(Json)]
};
let mut new_item_body = s.clone();
new_item_body.attrs.insert(0, attribute);
new_mod_types_items.push(syn::Item::Struct(new_item_body));
}
}
syn::Item::Enum(e) => {
let ident_name = e.ident.to_string();
let mut new_item_body = e.clone();
// Serialise enums as JSON
let attribute: syn::Attribute = parse_quote! {
#[butane_type(Json)]
};
new_item_body.attrs.insert(0, attribute);
new_mod_types_items.push(syn::Item::Enum(new_item_body));
}
_ => new_mod_types_items.push(item),
}
}
mod_types.content = Some((brace, new_mod_types_items));
let pub_mod_migrations: syn::Stmt = parse_quote! {
pub mod butane_migrations;
};
let pub_mod_migrations: syn::Item = cast!(&pub_mod_migrations, syn::Stmt::Item).to_owned();
let new_item = syn::Item::Mod(mod_types);
let mut modified = input;
modified.items = vec![pub_mod_migrations, new_item];
modified
}
Progenitor after syn – lib-erty
fn transform_table(struct_name: String, input: syn::ItemStruct) -> syn::ItemStruct {
let mut new_struct = input;
for field in new_struct.fields.iter_mut() {
let name = field.ident.as_ref().unwrap().to_string();
if name.replace('_', "") == format!("{}id", struct_name.to_lowercase()) {
// This branch is for the primary key field
let attribute: syn::Attribute = parse_quote! {
#[pk]
};
field.attrs.insert(0, attribute);
} else {
// Any other field
match field.ty.clone() {
syn::Type::Path(p) => {
let type_name = p.path.segments[0].ident.to_string();
if type_name == "Vec" {
// If the Vec is of another table, replace Vec with Many.
// Currently this does not check if the target is a table.
// Also remove the `skip_serializing_if`.
// See https://github.com/Electron100/butane/issues/31
let mut new_field_type = p.clone();
let attribute: syn::Attribute = parse_quote! {
#[serde(default)]
};
field.attrs = vec![attribute];
new_field_type.path.segments[0].ident =
syn::Ident::new("Many", Span::call_site());
field.ty = syn::Type::Path(new_field_type);
} else if type_name == "Option" {
// Replace Option<T> with <Option<ForeignKey<T>>
// if T is another table.
let target: syn::AngleBracketedGenericArguments = cast!(
p.path.segments[0].arguments.clone(),
syn::PathArguments::AngleBracketed
);
let target: syn::Type =
cast!(target.args[0].clone(), syn::GenericArgument::Type);
let target: syn::TypePath = cast!(target, syn::Type::Path);
let target_type_name = target.path.segments[0].ident.to_string();
if TABLE_SCHEMAS.contains(&target_type_name.as_str()) {
// found reference to another table
let new_field_type: syn::TypePath = parse_quote! {
Option<ForeignKey<#target>>
};
field.ty = syn::Type::Path(new_field_type);
}
}
}
_ => {
panic!("cargo:warning=non path type {:?} {:?}nn", name, field.ty);
}
}
}
}
Progenitor after syn – lib-erty
fn transform_table(struct_name: String, input: syn::ItemStruct) ->
syn::ItemStruct {
let mut new_struct = input;
for field in new_struct.fields.iter_mut() {
let name = field.ident.as_ref().unwrap().to_string();
if name.replace('_', "") == format!("{}id", struct_name.to_lowercase())
{
// This branch is for the primary key field
let attribute: syn::Attribute = parse_quote! {
#[pk]
};
field.attrs.insert(0, attribute);
} else {
}
}
let attribute: syn::Attribute = parse_quote! {
#[model]
};
new_struct.attrs.insert(0, attribute);
new_struct
}
...
Progenitor after syn – sample code
#[model]
#[derive(Clone, Debug, Default, Deserialize, Dummy, PartialEq,
Serialize, actix_default_responder::JsonResponder,
utoipa::ToSchema)]
pub struct Patient {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub age: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub dob: Option<chrono::DateTime<chrono::offset::Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[pk]
pub patient_id: uuid::Uuid,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub sex: Option<PatientSexEnum>,
}
The wages of syn is ...
This work is licensed under
a Creative Commons Attribution-ShareAlike 3.0 Unported License.
It makes use of the works of
Kelly Loves Whales and Nick Merritt.

More Related Content

Similar to syn

Mockito with a hint of PowerMock
Mockito with a hint of PowerMockMockito with a hint of PowerMock
Mockito with a hint of PowerMockYing Zhang
 
Quicli - From zero to a full CLI application in a few lines of Rust
Quicli - From zero to a full CLI application in a few lines of RustQuicli - From zero to a full CLI application in a few lines of Rust
Quicli - From zero to a full CLI application in a few lines of RustDamien Castelltort
 
Checking Oracle VM VirtualBox. Part 2
Checking Oracle VM VirtualBox. Part 2Checking Oracle VM VirtualBox. Part 2
Checking Oracle VM VirtualBox. Part 2Andrey Karpov
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleThierry Wasylczenko
 
Sinatra and JSONQuery Web Service
Sinatra and JSONQuery Web ServiceSinatra and JSONQuery Web Service
Sinatra and JSONQuery Web Servicevvatikiotis
 
Toonz code leaves much to be desired
Toonz code leaves much to be desiredToonz code leaves much to be desired
Toonz code leaves much to be desiredPVS-Studio
 
Perl: Hate it for the Right Reasons
Perl: Hate it for the Right ReasonsPerl: Hate it for the Right Reasons
Perl: Hate it for the Right ReasonsMatt Follett
 
Integrating Flex And Rails With Ruby Amf
Integrating Flex And Rails With Ruby AmfIntegrating Flex And Rails With Ruby Amf
Integrating Flex And Rails With Ruby Amfrailsconf
 
Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Arnaud Giuliani
 
Testing of javacript
Testing of javacriptTesting of javacript
Testing of javacriptLei Kang
 
Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016PVS-Studio
 
Checking the Cross-Platform Framework Cocos2d-x
Checking the Cross-Platform Framework Cocos2d-xChecking the Cross-Platform Framework Cocos2d-x
Checking the Cross-Platform Framework Cocos2d-xAndrey Karpov
 
SystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummarySystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummaryAmal Khailtash
 
How I hack on puppet modules
How I hack on puppet modulesHow I hack on puppet modules
How I hack on puppet modulesKris Buytaert
 
Rooted 2010 ppp
Rooted 2010 pppRooted 2010 ppp
Rooted 2010 pppnoc_313
 
Writing and Publishing Puppet Modules - PuppetConf 2014
Writing and Publishing Puppet Modules - PuppetConf 2014Writing and Publishing Puppet Modules - PuppetConf 2014
Writing and Publishing Puppet Modules - PuppetConf 2014Puppet
 

Similar to syn (20)

Mockito with a hint of PowerMock
Mockito with a hint of PowerMockMockito with a hint of PowerMock
Mockito with a hint of PowerMock
 
C++ Core Guidelines
C++ Core GuidelinesC++ Core Guidelines
C++ Core Guidelines
 
Quicli - From zero to a full CLI application in a few lines of Rust
Quicli - From zero to a full CLI application in a few lines of RustQuicli - From zero to a full CLI application in a few lines of Rust
Quicli - From zero to a full CLI application in a few lines of Rust
 
Checking Oracle VM VirtualBox. Part 2
Checking Oracle VM VirtualBox. Part 2Checking Oracle VM VirtualBox. Part 2
Checking Oracle VM VirtualBox. Part 2
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradle
 
Sinatra and JSONQuery Web Service
Sinatra and JSONQuery Web ServiceSinatra and JSONQuery Web Service
Sinatra and JSONQuery Web Service
 
Toonz code leaves much to be desired
Toonz code leaves much to be desiredToonz code leaves much to be desired
Toonz code leaves much to be desired
 
Perl: Hate it for the Right Reasons
Perl: Hate it for the Right ReasonsPerl: Hate it for the Right Reasons
Perl: Hate it for the Right Reasons
 
Integrating Flex And Rails With Ruby Amf
Integrating Flex And Rails With Ruby AmfIntegrating Flex And Rails With Ruby Amf
Integrating Flex And Rails With Ruby Amf
 
Flex With Rubyamf
Flex With RubyamfFlex With Rubyamf
Flex With Rubyamf
 
Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017
 
Testing of javacript
Testing of javacriptTesting of javacript
Testing of javacript
 
Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016
 
Checking the Cross-Platform Framework Cocos2d-x
Checking the Cross-Platform Framework Cocos2d-xChecking the Cross-Platform Framework Cocos2d-x
Checking the Cross-Platform Framework Cocos2d-x
 
SystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummarySystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features Summary
 
How I hack on puppet modules
How I hack on puppet modulesHow I hack on puppet modules
How I hack on puppet modules
 
Sprockets
SprocketsSprockets
Sprockets
 
Rooted 2010 ppp
Rooted 2010 pppRooted 2010 ppp
Rooted 2010 ppp
 
C# 6.0 Preview
C# 6.0 PreviewC# 6.0 Preview
C# 6.0 Preview
 
Writing and Publishing Puppet Modules - PuppetConf 2014
Writing and Publishing Puppet Modules - PuppetConf 2014Writing and Publishing Puppet Modules - PuppetConf 2014
Writing and Publishing Puppet Modules - PuppetConf 2014
 

More from John Vandenberg

Rust & Python : Python WA October meetup
Rust & Python : Python WA October meetupRust & Python : Python WA October meetup
Rust & Python : Python WA October meetupJohn Vandenberg
 
Rust ORMs and Migrations
Rust ORMs and MigrationsRust ORMs and Migrations
Rust ORMs and MigrationsJohn Vandenberg
 
Rust & Python : Rust WA meetup 1
Rust & Python : Rust WA meetup 1Rust & Python : Rust WA meetup 1
Rust & Python : Rust WA meetup 1John Vandenberg
 
Besut Kode seminar Lampung
Besut Kode seminar LampungBesut Kode seminar Lampung
Besut Kode seminar LampungJohn Vandenberg
 
Besut Kode Seminar Malang
Besut Kode Seminar MalangBesut Kode Seminar Malang
Besut Kode Seminar MalangJohn Vandenberg
 
Wikimedia indigenous voices
Wikimedia indigenous voicesWikimedia indigenous voices
Wikimedia indigenous voicesJohn Vandenberg
 
SGU - Creating an English Wikipedia draft
SGU - Creating an English Wikipedia draftSGU - Creating an English Wikipedia draft
SGU - Creating an English Wikipedia draftJohn Vandenberg
 
SGU Wikimedia in Education overview
SGU Wikimedia in Education overviewSGU Wikimedia in Education overview
SGU Wikimedia in Education overviewJohn Vandenberg
 
SLQ Wikipedia workshop: creating a draft
SLQ Wikipedia workshop: creating a draftSLQ Wikipedia workshop: creating a draft
SLQ Wikipedia workshop: creating a draftJohn Vandenberg
 
Intelligent info 2012 wikipedia
Intelligent info 2012 wikipediaIntelligent info 2012 wikipedia
Intelligent info 2012 wikipediaJohn Vandenberg
 

More from John Vandenberg (15)

Rust & Python : Python WA October meetup
Rust & Python : Python WA October meetupRust & Python : Python WA October meetup
Rust & Python : Python WA October meetup
 
butane Rust ORM
butane Rust ORMbutane Rust ORM
butane Rust ORM
 
Rust ORMs and Migrations
Rust ORMs and MigrationsRust ORMs and Migrations
Rust ORMs and Migrations
 
Rust & Python : Rust WA meetup 1
Rust & Python : Rust WA meetup 1Rust & Python : Rust WA meetup 1
Rust & Python : Rust WA meetup 1
 
Besut Kode seminar Lampung
Besut Kode seminar LampungBesut Kode seminar Lampung
Besut Kode seminar Lampung
 
Besut Kode Seminar Malang
Besut Kode Seminar MalangBesut Kode Seminar Malang
Besut Kode Seminar Malang
 
Besut Kode - Workshop 2
Besut Kode - Workshop 2Besut Kode - Workshop 2
Besut Kode - Workshop 2
 
Besut Kode - Workshop 1
Besut Kode - Workshop 1Besut Kode - Workshop 1
Besut Kode - Workshop 1
 
Besut Kode Challenge 1
Besut Kode Challenge 1Besut Kode Challenge 1
Besut Kode Challenge 1
 
Wikimedia indigenous voices
Wikimedia indigenous voicesWikimedia indigenous voices
Wikimedia indigenous voices
 
SGU - Creating an English Wikipedia draft
SGU - Creating an English Wikipedia draftSGU - Creating an English Wikipedia draft
SGU - Creating an English Wikipedia draft
 
SGU Wikimedia in Education overview
SGU Wikimedia in Education overviewSGU Wikimedia in Education overview
SGU Wikimedia in Education overview
 
Commons
CommonsCommons
Commons
 
SLQ Wikipedia workshop: creating a draft
SLQ Wikipedia workshop: creating a draftSLQ Wikipedia workshop: creating a draft
SLQ Wikipedia workshop: creating a draft
 
Intelligent info 2012 wikipedia
Intelligent info 2012 wikipediaIntelligent info 2012 wikipedia
Intelligent info 2012 wikipedia
 

Recently uploaded

The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfkalichargn70th171
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyFrank van der Linden
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 

Recently uploaded (20)

The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The Ugly
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 

syn

  • 1. The wages of syn is ... by @jayvdb John Mark Vandenberg
  • 10. Romans 6:23 Rust crates.io
  • 11. Romans 6:23 Rust crates.io
  • 12. Java, with mustache templates, with JavaScript CLI wrapper, and does not support adding custom “derive” to the structs, or easily using custom templates openapi-generator Rust, but only supports OpenAPI v2. Downgrading v3 to v2 is lossy, but acceptable for models-only. A small python script used to downgrade. No templating for custom derive. paperclip Rust, OpenAPI v3, YAML, Jinja templates. Builds, works well, but the templates are not as good as progenitor. schema-tools Rust, OpenAPI v3, no YAML. Two pulls requests and we’re 100% Rust, OpenAPI v3, YAML. Custom derive require hacks. progenitor 01 01 02 02 03 03 04 04
  • 13. Java, with mustache templates, with JavaScript CLI wrapper, and does not support adding custom “derive” to the structs, or easily using custom templates openapi-generator Rust, but only supports OpenAPI v2. Downgrading v3 to v2 is lossy, but acceptable for models-only. A small python script used to downgrade. No templating for custom derive. paperclip Rust, OpenAPI v3, YAML, Jinja templates. Builds, works well, but refuses to install. schema-tools Rust, OpenAPI v3, no YAML. Two pulls requests and we’re 100% Rust, OpenAPI v3, YAML. Custom derive require hacks. progenitor 01 01 02 02 03 03 04 04
  • 14. What is Progenitor? Progenitor is a Rust crate for generating opinionated clients from API descriptions in the OpenAPI 3.0.x specification. It makes use of Rust futures for async API calls and Streams for paginated interfaces. It generates a type called Client with methods that correspond to the operations specified in the OpenAPI document.
  • 15. Why use Progenitor? OpenAPI between services: * Standards based * Keeps use honest * Free code
  • 16. Progenitor before syn – forking hell
  • 17. Progenitor before syn – forking hell
  • 18. Progenitor before syn – forking hell
  • 19. Progenitor before syn – forking hell
  • 20. Progenitor before syn – forking hell
  • 21. Progenitor before syn – forking hell
  • 22. Progenitor before syn – forking hell
  • 23. fn main() { let mut project_root = lets_find_up::find_up("Makefile.toml").unwrap().unwrap(); project_root.pop(); // Drop filename from path let input_yaml = format!("{}/openapi.yaml", project_root.display()); let spec = load_spec(input_yaml); // The use of `with_patch` here is to provide similar behaviour to // unmerged https://github.com/oxidecomputer/typify/pull/184 let mut schema_names: ; for schema_name in schema_names.iter().cloned() { if !is_pascal_case(&schema_name) { panic!("{schema_name} is not pascal case which will cause bugs."); } let mut patch = progenitor_impl::TypePatch::default(); // The enums have a Default impl added by typify if !schema_name.ends_with("Enum") // MySpecialEnum has a custom Default impl added in elsewhere. && schema_name != "MySpecialEnum" { patch.with_derive("Default"); } if !TABLE_SCHEMAS.contains(&schema_name.as_str()) { patch.with_derive("FieldType"); } settings.with_patch(schema_name, &patch); } let input = generate_rust(&spec, &settings); Progenitor after syn – lib-erty ...
  • 24. fn main() { let input = generate_rust(&spec, &settings); let modified = transform_rust(input); let out_filename = format!("{}/rust/models/src/lib.rs", project_root.display()); write_rust(out_filename, &modified); } Progenitor after syn – lib-erty ... fn generate_rust( spec: &OpenAPI, settings: &progenitor_impl::GenerationSettings ) -> syn::File { let mut generator = progenitor_impl::Generator::new(settings); let original_tokens = generator.generate_tokens(spec).unwrap(); let ast: syn::File = syn::parse2(original_tokens).unwrap(); ast }
  • 25. Progenitor after syn – lib-erty fn transform_rust(input: syn::File) -> syn::File { let extra_butane_use: syn::Stmt = parse_quote! { use butane::{ butane_type, model, ButaneJson, DataObject, FieldType, ForeignKey, FromSql, Many, SqlType, SqlVal, SqlValRef, ToSql, }; }; let extra_fake_use: syn::Stmt = parse_quote! { use fake::{Dummy, Fake}; }; let extra_rand_use: syn::Stmt = parse_quote! { use rand; }; let use_butane_item: &syn::Item = cast!(&extra_butane_use, syn::Stmt::Item); let use_fake_item: &syn::Item = cast!(&extra_fake_use, syn::Stmt::Item); let use_rand_item: &syn::Item = cast!(&extra_rand_use, syn::Stmt::Item); // Only the 'pub mod types { .. }' item from the input is wanted. // i.e. remove the reqwest client const MOD_TYPES_INDEX: usize = 3; let mut mod_types: syn::ItemMod = cast!(&input.items[MOD_TYPES_INDEX], syn::Item::Mod).clone(); let (brace, mod_types_items) = mod_types.content.clone().unwrap(); let mut new_mod_types_items: Vec<syn::Item> = vec![]; new_mod_types_items.push(use_butane_item.clone()); new_mod_types_items.push(use_fake_item.clone()); new_mod_types_items.push(use_rand_item.clone()); for item in mod_types_items { match item.clone() { syn::Item::Struct(s) => { let ident_name = s.ident.to_string(); if TABLE_SCHEMAS.contains(&ident_name.as_str()) { // This branch is for the tables let new_struct = transform_table(ident_name, s); new_mod_types_items.push(syn::Item::Struct(new_struct)); } else { // Serialise non-table schemas as JSON let attribute: syn::Attribute = parse_quote! { #[butane_type(Json)] }; let mut new_item_body = s.clone(); new_item_body.attrs.insert(0, attribute); new_mod_types_items.push(syn::Item::Struct(new_item_body)); } } syn::Item::Enum(e) => { let ident_name = e.ident.to_string(); let mut new_item_body = e.clone(); // Serialise enums as JSON let attribute: syn::Attribute = parse_quote! { #[butane_type(Json)] }; new_item_body.attrs.insert(0, attribute); new_mod_types_items.push(syn::Item::Enum(new_item_body)); } _ => new_mod_types_items.push(item), } } mod_types.content = Some((brace, new_mod_types_items)); let pub_mod_migrations: syn::Stmt = parse_quote! { pub mod butane_migrations; }; let pub_mod_migrations: syn::Item = cast!(&pub_mod_migrations, syn::Stmt::Item).to_owned(); let new_item = syn::Item::Mod(mod_types); let mut modified = input; modified.items = vec![pub_mod_migrations, new_item]; modified }
  • 26. Progenitor after syn – lib-erty fn transform_table(struct_name: String, input: syn::ItemStruct) -> syn::ItemStruct { let mut new_struct = input; for field in new_struct.fields.iter_mut() { let name = field.ident.as_ref().unwrap().to_string(); if name.replace('_', "") == format!("{}id", struct_name.to_lowercase()) { // This branch is for the primary key field let attribute: syn::Attribute = parse_quote! { #[pk] }; field.attrs.insert(0, attribute); } else { // Any other field match field.ty.clone() { syn::Type::Path(p) => { let type_name = p.path.segments[0].ident.to_string(); if type_name == "Vec" { // If the Vec is of another table, replace Vec with Many. // Currently this does not check if the target is a table. // Also remove the `skip_serializing_if`. // See https://github.com/Electron100/butane/issues/31 let mut new_field_type = p.clone(); let attribute: syn::Attribute = parse_quote! { #[serde(default)] }; field.attrs = vec![attribute]; new_field_type.path.segments[0].ident = syn::Ident::new("Many", Span::call_site()); field.ty = syn::Type::Path(new_field_type); } else if type_name == "Option" { // Replace Option<T> with <Option<ForeignKey<T>> // if T is another table. let target: syn::AngleBracketedGenericArguments = cast!( p.path.segments[0].arguments.clone(), syn::PathArguments::AngleBracketed ); let target: syn::Type = cast!(target.args[0].clone(), syn::GenericArgument::Type); let target: syn::TypePath = cast!(target, syn::Type::Path); let target_type_name = target.path.segments[0].ident.to_string(); if TABLE_SCHEMAS.contains(&target_type_name.as_str()) { // found reference to another table let new_field_type: syn::TypePath = parse_quote! { Option<ForeignKey<#target>> }; field.ty = syn::Type::Path(new_field_type); } } } _ => { panic!("cargo:warning=non path type {:?} {:?}nn", name, field.ty); } } } }
  • 27. Progenitor after syn – lib-erty fn transform_table(struct_name: String, input: syn::ItemStruct) -> syn::ItemStruct { let mut new_struct = input; for field in new_struct.fields.iter_mut() { let name = field.ident.as_ref().unwrap().to_string(); if name.replace('_', "") == format!("{}id", struct_name.to_lowercase()) { // This branch is for the primary key field let attribute: syn::Attribute = parse_quote! { #[pk] }; field.attrs.insert(0, attribute); } else { } } let attribute: syn::Attribute = parse_quote! { #[model] }; new_struct.attrs.insert(0, attribute); new_struct } ...
  • 28. Progenitor after syn – sample code #[model] #[derive(Clone, Debug, Default, Deserialize, Dummy, PartialEq, Serialize, actix_default_responder::JsonResponder, utoipa::ToSchema)] pub struct Patient { #[serde(default, skip_serializing_if = "Option::is_none")] pub age: Option<i64>, #[serde(default, skip_serializing_if = "Option::is_none")] pub dob: Option<chrono::DateTime<chrono::offset::Utc>>, #[serde(default, skip_serializing_if = "Option::is_none")] pub name: Option<String>, #[pk] pub patient_id: uuid::Uuid, #[serde(default, skip_serializing_if = "Option::is_none")] pub sex: Option<PatientSexEnum>, }
  • 29. The wages of syn is ...
  • 30. This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. It makes use of the works of Kelly Loves Whales and Nick Merritt.