use sigil_stitch::lang::scala::Scala;
use sigil_stitch::prelude::*;
fn main() {
println!("=== Builder API ===\n");
let builder_output = builder_approach();
println!("{builder_output}");
println!("=== sigil_quote! Macro ===\n");
let macro_output = macro_approach();
println!("{macro_output}");
}
fn build_shared_types() -> (TypeSpec, TypeSpec) {
let repo = TypeSpec::builder("Repository", TypeKind::Interface)
.add_type_param(TypeParamSpec::new("T"))
.add_method(
FunSpec::builder("findById")
.returns(TypeName::optional(TypeName::primitive("T")))
.add_param(ParameterSpec::new("id", TypeName::primitive("Long")).unwrap())
.build()
.unwrap(),
)
.add_method(
FunSpec::builder("save")
.add_param(ParameterSpec::new("entity", TypeName::primitive("T")).unwrap())
.returns(TypeName::primitive("Unit"))
.build()
.unwrap(),
)
.build()
.unwrap();
let user = TypeSpec::builder("User", TypeKind::Struct)
.doc("A user entity.")
.add_primary_constructor_param(
ParameterSpec::new("id", TypeName::primitive("Long")).unwrap(),
)
.add_primary_constructor_param(
ParameterSpec::new("name", TypeName::primitive("String")).unwrap(),
)
.add_primary_constructor_param(
ParameterSpec::new("email", TypeName::primitive("String")).unwrap(),
)
.build()
.unwrap();
(repo, user)
}
fn builder_approach() -> String {
let list_buffer = TypeName::importable("scala.collection.mutable", "ListBuffer");
let (repo, user) = build_shared_types();
let mut sort_body = CodeBlock::builder();
sort_body.add_statement("items.sorted", ());
let sort_fn = FunSpec::builder("sortItems")
.add_type_param(TypeParamSpec::new("T").with_context_bound(TypeName::primitive("Ordering")))
.add_param(
ParameterSpec::new(
"items",
TypeName::generic(TypeName::primitive("List"), vec![TypeName::primitive("T")]),
)
.unwrap(),
)
.returns(TypeName::generic(
TypeName::primitive("List"),
vec![TypeName::primitive("T")],
))
.body(sort_body.build().unwrap())
.build()
.unwrap();
let mut collect_body = CodeBlock::builder();
collect_body.add("val buf = new %T[String]()", (list_buffer,));
collect_body.add_line();
collect_body.add("buf += name", ());
collect_body.add_line();
collect_body.add("buf.toList", ());
let collect_fn = FunSpec::builder("collectNames")
.add_param(ParameterSpec::new("name", TypeName::primitive("String")).unwrap())
.returns(TypeName::generic(
TypeName::primitive("List"),
vec![TypeName::primitive("String")],
))
.body(collect_body.build().unwrap())
.build()
.unwrap();
let functor = TypeSpec::builder("Functor", TypeKind::Interface)
.add_type_param(TypeParamSpec::new("F").with_kind(TypeParamKind::Constructor1))
.add_method(
FunSpec::builder("map")
.add_type_param(TypeParamSpec::new("A"))
.add_type_param(TypeParamSpec::new("B"))
.add_param(
ParameterSpec::new(
"fa",
TypeName::generic(TypeName::primitive("F"), vec![TypeName::primitive("A")]),
)
.unwrap(),
)
.add_param(
ParameterSpec::new(
"f",
TypeName::function(
vec![TypeName::primitive("A")],
TypeName::primitive("B"),
),
)
.unwrap(),
)
.returns(TypeName::generic(
TypeName::primitive("F"),
vec![TypeName::primitive("B")],
))
.build()
.unwrap(),
)
.build()
.unwrap();
FileSpec::builder_with("User.scala", Scala::new())
.add_type(repo)
.add_type(user)
.add_type(functor)
.add_function(sort_fn)
.add_function(collect_fn)
.build()
.unwrap()
.render(80)
.unwrap()
}
fn macro_approach() -> String {
let list_buffer = TypeName::importable("scala.collection.mutable", "ListBuffer");
let (repo, user) = build_shared_types();
let sort_body = sigil_quote!(Scala {
items.sorted
})
.unwrap();
let sort_fn = FunSpec::builder("sortItems")
.add_type_param(TypeParamSpec::new("T").with_context_bound(TypeName::primitive("Ordering")))
.add_param(
ParameterSpec::new(
"items",
TypeName::generic(TypeName::primitive("List"), vec![TypeName::primitive("T")]),
)
.unwrap(),
)
.returns(TypeName::generic(
TypeName::primitive("List"),
vec![TypeName::primitive("T")],
))
.body(sort_body)
.build()
.unwrap();
let collect_body = sigil_quote!(Scala {
val buf = new $T(list_buffer)[String]()
buf += name
buf.toList
})
.unwrap();
let collect_fn = FunSpec::builder("collectNames")
.add_param(ParameterSpec::new("name", TypeName::primitive("String")).unwrap())
.returns(TypeName::generic(
TypeName::primitive("List"),
vec![TypeName::primitive("String")],
))
.body(collect_body)
.build()
.unwrap();
let functor = TypeSpec::builder("Functor", TypeKind::Interface)
.add_type_param(TypeParamSpec::new("F").with_kind(TypeParamKind::Constructor1))
.add_method(
FunSpec::builder("map")
.add_type_param(TypeParamSpec::new("A"))
.add_type_param(TypeParamSpec::new("B"))
.add_param(
ParameterSpec::new(
"fa",
TypeName::generic(TypeName::primitive("F"), vec![TypeName::primitive("A")]),
)
.unwrap(),
)
.add_param(
ParameterSpec::new(
"f",
TypeName::function(
vec![TypeName::primitive("A")],
TypeName::primitive("B"),
),
)
.unwrap(),
)
.returns(TypeName::generic(
TypeName::primitive("F"),
vec![TypeName::primitive("B")],
))
.build()
.unwrap(),
)
.build()
.unwrap();
FileSpec::builder_with("User.scala", Scala::new())
.add_type(repo)
.add_type(user)
.add_type(functor)
.add_function(sort_fn)
.add_function(collect_fn)
.build()
.unwrap()
.render(80)
.unwrap()
}