torn_api_codegen/model/
scope.rs1use heck::ToUpperCamelCase;
2use indexmap::IndexMap;
3use proc_macro2::TokenStream;
4use quote::{format_ident, quote};
5
6use super::path::{Path, PathSegment};
7
8pub struct Scope {
9 pub name: String,
10 pub mod_name: String,
11 pub members: Vec<Path>,
12}
13
14impl Scope {
15 pub fn from_paths(paths: Vec<Path>) -> Vec<Scope> {
16 let mut map = IndexMap::new();
17
18 for path in paths {
19 let Some(PathSegment::Constant(first_seg)) = path.segments.first() else {
20 continue;
21 };
22
23 map.entry(first_seg.to_owned())
24 .or_insert_with(|| Scope {
25 name: format!("{}Scope", first_seg.to_upper_camel_case()),
26 mod_name: first_seg.clone(),
27 members: Vec::new(),
28 })
29 .members
30 .push(path);
31 }
32
33 map.into_values().collect()
34 }
35
36 pub fn codegen(&self) -> Option<TokenStream> {
37 let name = format_ident!("{}", self.name);
38 let bulk_name = format_ident!("Bulk{}", self.name);
39
40 let mut functions = Vec::with_capacity(self.members.len());
41 let mut bulk_functions = Vec::with_capacity(self.members.len());
42
43 for member in &self.members {
44 if let Some(code) = member.codegen_scope_call() {
45 functions.push(code);
46 }
47 if let Some(code) = member.codegen_bulk_scope_call() {
48 bulk_functions.push(code);
49 }
50 }
51
52 Some(quote! {
53 #[allow(dead_code)]
54 pub struct #name<E>(E)
55 where
56 E: crate::executor::Executor;
57
58 impl<E> #name<E>
59 where
60 E: crate::executor::Executor
61 {
62 pub fn new(executor: E) -> Self {
63 Self(executor)
64 }
65
66 #(#functions)*
67 }
68
69 #[allow(dead_code)]
70 pub struct #bulk_name<E> where
71 E: crate::executor::BulkExecutor,
72 {
73 executor: E,
74 }
75
76 impl<E> #bulk_name<E>
77 where
78 E: crate::executor::BulkExecutor
79 {
80 pub fn new(executor: E) -> Self {
81 Self {
82 executor,
83 }
84 }
85
86 #(#bulk_functions)*
87 }
88 })
89 }
90}