1 | //! A representation of the Abstract Syntax Tree of a Rust program, |
2 | //! with all the added metadata necessary to generate Wasm bindings |
3 | //! for it. |
4 | |
5 | use crate::{util::ShortHash, Diagnostic}; |
6 | use proc_macro2::{Ident, Span}; |
7 | use std::hash::{Hash, Hasher}; |
8 | use syn::Path; |
9 | use wasm_bindgen_shared as shared; |
10 | |
11 | /// An abstract syntax tree representing a rust program. Contains |
12 | /// extra information for joining up this rust code with javascript. |
13 | #[cfg_attr (feature = "extra-traits" , derive(Debug))] |
14 | #[derive (Clone)] |
15 | pub struct Program { |
16 | /// rust -> js interfaces |
17 | pub exports: Vec<Export>, |
18 | /// js -> rust interfaces |
19 | pub imports: Vec<Import>, |
20 | /// linked-to modules |
21 | pub linked_modules: Vec<ImportModule>, |
22 | /// rust enums |
23 | pub enums: Vec<Enum>, |
24 | /// rust structs |
25 | pub structs: Vec<Struct>, |
26 | /// custom typescript sections to be included in the definition file |
27 | pub typescript_custom_sections: Vec<LitOrExpr>, |
28 | /// Inline JS snippets |
29 | pub inline_js: Vec<String>, |
30 | /// Path to wasm_bindgen |
31 | pub wasm_bindgen: Path, |
32 | /// Path to js_sys |
33 | pub js_sys: Path, |
34 | /// Path to wasm_bindgen_futures |
35 | pub wasm_bindgen_futures: Path, |
36 | } |
37 | |
38 | impl Default for Program { |
39 | fn default() -> Self { |
40 | Self { |
41 | exports: Default::default(), |
42 | imports: Default::default(), |
43 | linked_modules: Default::default(), |
44 | enums: Default::default(), |
45 | structs: Default::default(), |
46 | typescript_custom_sections: Default::default(), |
47 | inline_js: Default::default(), |
48 | wasm_bindgen: syn::parse_quote! { wasm_bindgen }, |
49 | js_sys: syn::parse_quote! { js_sys }, |
50 | wasm_bindgen_futures: syn::parse_quote! { wasm_bindgen_futures }, |
51 | } |
52 | } |
53 | } |
54 | |
55 | impl Program { |
56 | /// Returns true if the Program is empty |
57 | pub fn is_empty(&self) -> bool { |
58 | self.exports.is_empty() |
59 | && self.imports.is_empty() |
60 | && self.enums.is_empty() |
61 | && self.structs.is_empty() |
62 | && self.typescript_custom_sections.is_empty() |
63 | && self.inline_js.is_empty() |
64 | } |
65 | |
66 | /// Name of the link function for a specific linked module |
67 | pub fn link_function_name(&self, idx: usize) -> String { |
68 | let hash: String = match &self.linked_modules[idx] { |
69 | ImportModule::Inline(idx: &usize, _) => ShortHash((1, &self.inline_js[*idx])).to_string(), |
70 | other: &ImportModule => ShortHash((0, other)).to_string(), |
71 | }; |
72 | format!("__wbindgen_link_ {}" , hash) |
73 | } |
74 | } |
75 | |
76 | /// An abstract syntax tree representing a link to a module in Rust. |
77 | /// In contrast to Program, LinkToModule must expand to an expression. |
78 | /// linked_modules of the inner Program must contain exactly one element |
79 | /// whose link is produced by the expression. |
80 | #[cfg_attr (feature = "extra-traits" , derive(Debug))] |
81 | #[derive (Clone)] |
82 | pub struct LinkToModule(pub Program); |
83 | |
84 | /// A rust to js interface. Allows interaction with rust objects/functions |
85 | /// from javascript. |
86 | #[cfg_attr (feature = "extra-traits" , derive(Debug))] |
87 | #[derive (Clone)] |
88 | pub struct Export { |
89 | /// Comments extracted from the rust source. |
90 | pub comments: Vec<String>, |
91 | /// The rust function |
92 | pub function: Function, |
93 | /// The class name in JS this is attached to |
94 | pub js_class: Option<String>, |
95 | /// The kind (static, named, regular) |
96 | pub method_kind: MethodKind, |
97 | /// The type of `self` (either `self`, `&self`, or `&mut self`) |
98 | pub method_self: Option<MethodSelf>, |
99 | /// The struct name, in Rust, this is attached to |
100 | pub rust_class: Option<Ident>, |
101 | /// The name of the rust function/method on the rust side. |
102 | pub rust_name: Ident, |
103 | /// Whether or not this function should be flagged as the Wasm start |
104 | /// function. |
105 | pub start: bool, |
106 | /// Path to wasm_bindgen |
107 | pub wasm_bindgen: Path, |
108 | /// Path to wasm_bindgen_futures |
109 | pub wasm_bindgen_futures: Path, |
110 | } |
111 | |
112 | /// The 3 types variations of `self`. |
113 | #[cfg_attr (feature = "extra-traits" , derive(Debug, PartialEq, Eq))] |
114 | #[derive (Copy, Clone)] |
115 | pub enum MethodSelf { |
116 | /// `self` |
117 | ByValue, |
118 | /// `&mut self` |
119 | RefMutable, |
120 | /// `&self` |
121 | RefShared, |
122 | } |
123 | |
124 | /// Things imported from a JS module (in an `extern` block) |
125 | #[cfg_attr (feature = "extra-traits" , derive(Debug))] |
126 | #[derive (Clone)] |
127 | pub struct Import { |
128 | /// The type of module being imported from, if any |
129 | pub module: Option<ImportModule>, |
130 | /// The namespace to access the item through, if any |
131 | pub js_namespace: Option<Vec<String>>, |
132 | /// The type of item being imported |
133 | pub kind: ImportKind, |
134 | } |
135 | |
136 | /// The possible types of module to import from |
137 | #[cfg_attr (feature = "extra-traits" , derive(Debug))] |
138 | #[derive (Clone)] |
139 | pub enum ImportModule { |
140 | /// Import from the named module, with relative paths interpreted |
141 | Named(String, Span), |
142 | /// Import from the named module, without interpreting paths |
143 | RawNamed(String, Span), |
144 | /// Import from an inline JS snippet |
145 | Inline(usize, Span), |
146 | } |
147 | |
148 | impl Hash for ImportModule { |
149 | fn hash<H: Hasher>(&self, h: &mut H) { |
150 | match self { |
151 | ImportModule::Named(name: &String, _) => (1u8, name).hash(state:h), |
152 | ImportModule::Inline(idx: &usize, _) => (2u8, idx).hash(state:h), |
153 | ImportModule::RawNamed(name: &String, _) => (3u8, name).hash(state:h), |
154 | } |
155 | } |
156 | } |
157 | |
158 | /// The type of item being imported |
159 | #[cfg_attr (feature = "extra-traits" , derive(Debug))] |
160 | #[derive (Clone)] |
161 | pub enum ImportKind { |
162 | /// Importing a function |
163 | Function(ImportFunction), |
164 | /// Importing a static value |
165 | Static(ImportStatic), |
166 | /// Importing a static string |
167 | String(ImportString), |
168 | /// Importing a type/class |
169 | Type(ImportType), |
170 | /// Importing a JS enum |
171 | Enum(StringEnum), |
172 | } |
173 | |
174 | /// A function being imported from JS |
175 | #[cfg_attr (feature = "extra-traits" , derive(Debug))] |
176 | #[derive (Clone)] |
177 | pub struct ImportFunction { |
178 | /// The full signature of the function |
179 | pub function: Function, |
180 | /// The name rust code will use |
181 | pub rust_name: Ident, |
182 | /// The type being returned |
183 | pub js_ret: Option<syn::Type>, |
184 | /// Whether to catch JS exceptions |
185 | pub catch: bool, |
186 | /// Whether the function is variadic on the JS side |
187 | pub variadic: bool, |
188 | /// Whether the function should use structural type checking |
189 | pub structural: bool, |
190 | /// Causes the Builder (See cli-support::js::binding::Builder) to error out if |
191 | /// it finds itself generating code for a function with this signature |
192 | pub assert_no_shim: bool, |
193 | /// The kind of function being imported |
194 | pub kind: ImportFunctionKind, |
195 | /// The shim name to use in the generated code. The 'shim' is a function that appears in |
196 | /// the generated JS as a wrapper around the actual function to import, performing any |
197 | /// necessary conversions (EG adding a try/catch to change a thrown error into a Result) |
198 | pub shim: Ident, |
199 | /// The doc comment on this import, if one is provided |
200 | pub doc_comment: String, |
201 | /// Path to wasm_bindgen |
202 | pub wasm_bindgen: Path, |
203 | /// Path to wasm_bindgen_futures |
204 | pub wasm_bindgen_futures: Path, |
205 | } |
206 | |
207 | /// The type of a function being imported |
208 | #[cfg_attr (feature = "extra-traits" , derive(Debug, PartialEq, Eq))] |
209 | #[derive (Clone)] |
210 | pub enum ImportFunctionKind { |
211 | /// A class method |
212 | Method { |
213 | /// The name of the class for this method, in JS |
214 | class: String, |
215 | /// The type of the class for this method, in Rust |
216 | ty: syn::Type, |
217 | /// The kind of method this is |
218 | kind: MethodKind, |
219 | }, |
220 | /// A standard function |
221 | Normal, |
222 | } |
223 | |
224 | /// The type of a method |
225 | #[cfg_attr (feature = "extra-traits" , derive(Debug, PartialEq, Eq))] |
226 | #[derive (Clone)] |
227 | pub enum MethodKind { |
228 | /// A class constructor |
229 | Constructor, |
230 | /// Any other kind of method |
231 | Operation(Operation), |
232 | } |
233 | |
234 | /// The operation performed by a class method |
235 | #[cfg_attr (feature = "extra-traits" , derive(Debug, PartialEq, Eq))] |
236 | #[derive (Clone)] |
237 | pub struct Operation { |
238 | /// Whether this method is static |
239 | pub is_static: bool, |
240 | /// The internal kind of this Operation |
241 | pub kind: OperationKind, |
242 | } |
243 | |
244 | /// The kind of operation performed by a method |
245 | #[cfg_attr (feature = "extra-traits" , derive(Debug, PartialEq, Eq))] |
246 | #[derive (Clone)] |
247 | pub enum OperationKind { |
248 | /// A standard method, nothing special |
249 | Regular, |
250 | /// A method for getting the value of the provided Ident or String |
251 | Getter(Option<String>), |
252 | /// A method for setting the value of the provided Ident or String |
253 | Setter(Option<String>), |
254 | /// A dynamically intercepted getter |
255 | IndexingGetter, |
256 | /// A dynamically intercepted setter |
257 | IndexingSetter, |
258 | /// A dynamically intercepted deleter |
259 | IndexingDeleter, |
260 | } |
261 | |
262 | /// The type of a static being imported |
263 | #[cfg_attr (feature = "extra-traits" , derive(Debug, PartialEq, Eq))] |
264 | #[derive (Clone)] |
265 | pub struct ImportStatic { |
266 | /// The visibility of this static in Rust |
267 | pub vis: syn::Visibility, |
268 | /// The type of static being imported |
269 | pub ty: syn::Type, |
270 | /// The name of the shim function used to access this static |
271 | pub shim: Ident, |
272 | /// The name of this static on the Rust side |
273 | pub rust_name: Ident, |
274 | /// The name of this static on the JS side |
275 | pub js_name: String, |
276 | /// Path to wasm_bindgen |
277 | pub wasm_bindgen: Path, |
278 | /// Version of `thread_local`, if any. |
279 | pub thread_local: Option<ThreadLocal>, |
280 | } |
281 | |
282 | /// Which version of the `thread_local` attribute is enabled. |
283 | #[derive (Copy, Clone, Debug, PartialEq, Eq)] |
284 | pub enum ThreadLocal { |
285 | /// V1. |
286 | V1, |
287 | /// V2. |
288 | V2, |
289 | } |
290 | |
291 | /// The type of a static string being imported |
292 | #[cfg_attr (feature = "extra-traits" , derive(Debug, PartialEq, Eq))] |
293 | #[derive (Clone)] |
294 | pub struct ImportString { |
295 | /// The visibility of this static string in Rust |
296 | pub vis: syn::Visibility, |
297 | /// The type specified by the user, which we only use to show an error if the wrong type is used. |
298 | pub ty: syn::Type, |
299 | /// The name of the shim function used to access this static |
300 | pub shim: Ident, |
301 | /// The name of this static on the Rust side |
302 | pub rust_name: Ident, |
303 | /// Path to wasm_bindgen |
304 | pub wasm_bindgen: Path, |
305 | /// Path to js_sys |
306 | pub js_sys: Path, |
307 | /// The string to export. |
308 | pub string: String, |
309 | /// Version of `thread_local`. |
310 | pub thread_local: ThreadLocal, |
311 | } |
312 | |
313 | /// The metadata for a type being imported |
314 | #[cfg_attr (feature = "extra-traits" , derive(Debug, PartialEq, Eq))] |
315 | #[derive (Clone)] |
316 | pub struct ImportType { |
317 | /// The visibility of this type in Rust |
318 | pub vis: syn::Visibility, |
319 | /// The name of this type on the Rust side |
320 | pub rust_name: Ident, |
321 | /// The name of this type on the JS side |
322 | pub js_name: String, |
323 | /// The custom attributes to apply to this type |
324 | pub attrs: Vec<syn::Attribute>, |
325 | /// The TS definition to generate for this type |
326 | pub typescript_type: Option<String>, |
327 | /// The doc comment applied to this type, if one exists |
328 | pub doc_comment: Option<String>, |
329 | /// The name of the shim to check instanceof for this type |
330 | pub instanceof_shim: String, |
331 | /// The name of the remote function to use for the generated is_type_of |
332 | pub is_type_of: Option<syn::Expr>, |
333 | /// The list of classes this extends, if any |
334 | pub extends: Vec<syn::Path>, |
335 | /// A custom prefix to add and attempt to fall back to, if the type isn't found |
336 | pub vendor_prefixes: Vec<Ident>, |
337 | /// If present, don't generate a `Deref` impl |
338 | pub no_deref: bool, |
339 | /// Path to wasm_bindgen |
340 | pub wasm_bindgen: Path, |
341 | } |
342 | |
343 | /// The metadata for a String Enum |
344 | #[cfg_attr (feature = "extra-traits" , derive(Debug, PartialEq, Eq))] |
345 | #[derive (Clone)] |
346 | pub struct StringEnum { |
347 | /// The Rust enum's visibility |
348 | pub vis: syn::Visibility, |
349 | /// The Rust enum's identifiers |
350 | pub name: Ident, |
351 | /// The name of this string enum in JS/TS code |
352 | pub js_name: String, |
353 | /// The Rust identifiers for the variants |
354 | pub variants: Vec<Ident>, |
355 | /// The JS string values of the variants |
356 | pub variant_values: Vec<String>, |
357 | /// The doc comments on this enum, if any |
358 | pub comments: Vec<String>, |
359 | /// Attributes to apply to the Rust enum |
360 | pub rust_attrs: Vec<syn::Attribute>, |
361 | /// Whether to generate a typescript definition for this enum |
362 | pub generate_typescript: bool, |
363 | /// Path to wasm_bindgen |
364 | pub wasm_bindgen: Path, |
365 | } |
366 | |
367 | /// Information about a function being imported or exported |
368 | #[cfg_attr (feature = "extra-traits" , derive(Debug))] |
369 | #[derive (Clone)] |
370 | pub struct Function { |
371 | /// The name of the function |
372 | pub name: String, |
373 | /// The span of the function's name in Rust code |
374 | pub name_span: Span, |
375 | /// Whether the function has a js_name attribute |
376 | pub renamed_via_js_name: bool, |
377 | /// The arguments to the function |
378 | pub arguments: Vec<FunctionArgumentData>, |
379 | /// The data of return type of the function |
380 | pub ret: Option<FunctionReturnData>, |
381 | /// Any custom attributes being applied to the function |
382 | pub rust_attrs: Vec<syn::Attribute>, |
383 | /// The visibility of this function in Rust |
384 | pub rust_vis: syn::Visibility, |
385 | /// Whether this is an `unsafe` function |
386 | pub r#unsafe: bool, |
387 | /// Whether this is an `async` function |
388 | pub r#async: bool, |
389 | /// Whether to generate a typescript definition for this function |
390 | pub generate_typescript: bool, |
391 | /// Whether to generate jsdoc documentation for this function |
392 | pub generate_jsdoc: bool, |
393 | /// Whether this is a function with a variadict parameter |
394 | pub variadic: bool, |
395 | } |
396 | |
397 | /// Information about a function's return |
398 | #[cfg_attr (feature = "extra-traits" , derive(Debug))] |
399 | #[derive (Clone)] |
400 | pub struct FunctionReturnData { |
401 | /// Specifies the type of the function's return |
402 | pub r#type: syn::Type, |
403 | /// Specifies the JS return type override |
404 | pub js_type: Option<String>, |
405 | /// Specifies the return description |
406 | pub desc: Option<String>, |
407 | } |
408 | |
409 | /// Information about a function's argument |
410 | #[cfg_attr (feature = "extra-traits" , derive(Debug))] |
411 | #[derive (Clone)] |
412 | pub struct FunctionArgumentData { |
413 | /// Specifies the type of the function's argument |
414 | pub pat_type: syn::PatType, |
415 | /// Specifies the JS argument name override |
416 | pub js_name: Option<String>, |
417 | /// Specifies the JS function argument type override |
418 | pub js_type: Option<String>, |
419 | /// Specifies the argument description |
420 | pub desc: Option<String>, |
421 | } |
422 | |
423 | /// Information about a Struct being exported |
424 | #[cfg_attr (feature = "extra-traits" , derive(Debug))] |
425 | #[derive (Clone)] |
426 | pub struct Struct { |
427 | /// The name of the struct in Rust code |
428 | pub rust_name: Ident, |
429 | /// The name of the struct in JS code |
430 | pub js_name: String, |
431 | /// All the fields of this struct to export |
432 | pub fields: Vec<StructField>, |
433 | /// The doc comments on this struct, if provided |
434 | pub comments: Vec<String>, |
435 | /// Whether this struct is inspectable (provides toJSON/toString properties to JS) |
436 | pub is_inspectable: bool, |
437 | /// Whether to generate a typescript definition for this struct |
438 | pub generate_typescript: bool, |
439 | /// Path to wasm_bindgen |
440 | pub wasm_bindgen: Path, |
441 | } |
442 | |
443 | /// The field of a struct |
444 | #[cfg_attr (feature = "extra-traits" , derive(Debug))] |
445 | #[derive (Clone)] |
446 | pub struct StructField { |
447 | /// The name of the field in Rust code |
448 | pub rust_name: syn::Member, |
449 | /// The name of the field in JS code |
450 | pub js_name: String, |
451 | /// The name of the struct this field is part of |
452 | pub struct_name: Ident, |
453 | /// Whether this value is read-only to JS |
454 | pub readonly: bool, |
455 | /// The type of this field |
456 | pub ty: syn::Type, |
457 | /// The name of the getter shim for this field |
458 | pub getter: Ident, |
459 | /// The name of the setter shim for this field |
460 | pub setter: Ident, |
461 | /// The doc comments on this field, if any |
462 | pub comments: Vec<String>, |
463 | /// Whether to generate a typescript definition for this field |
464 | pub generate_typescript: bool, |
465 | /// Whether to generate jsdoc documentation for this field |
466 | pub generate_jsdoc: bool, |
467 | /// The span of the `#[wasm_bindgen(getter_with_clone)]` attribute applied |
468 | /// to this field, if any. |
469 | /// |
470 | /// If this is `Some`, the auto-generated getter for this field must clone |
471 | /// the field instead of copying it. |
472 | pub getter_with_clone: Option<Span>, |
473 | /// Path to wasm_bindgen |
474 | pub wasm_bindgen: Path, |
475 | } |
476 | |
477 | /// The metadata for an Enum |
478 | #[cfg_attr (feature = "extra-traits" , derive(Debug, PartialEq, Eq))] |
479 | #[derive (Clone)] |
480 | pub struct Enum { |
481 | /// The name of this enum in Rust code |
482 | pub rust_name: Ident, |
483 | /// The name of this enum in JS code |
484 | pub js_name: String, |
485 | /// Whether the variant values and hole are signed, meaning that they |
486 | /// represent the bits of a `i32` value. |
487 | pub signed: bool, |
488 | /// The variants provided by this enum |
489 | pub variants: Vec<Variant>, |
490 | /// The doc comments on this enum, if any |
491 | pub comments: Vec<String>, |
492 | /// The value to use for a `none` variant of the enum |
493 | pub hole: u32, |
494 | /// Whether to generate a typescript definition for this enum |
495 | pub generate_typescript: bool, |
496 | /// Path to wasm_bindgen |
497 | pub wasm_bindgen: Path, |
498 | } |
499 | |
500 | /// The variant of an enum |
501 | #[cfg_attr (feature = "extra-traits" , derive(Debug, PartialEq, Eq))] |
502 | #[derive (Clone)] |
503 | pub struct Variant { |
504 | /// The name of this variant |
505 | pub name: Ident, |
506 | /// The backing value of this variant |
507 | pub value: u32, |
508 | /// The doc comments on this variant, if any |
509 | pub comments: Vec<String>, |
510 | } |
511 | |
512 | /// Unused, the type of an argument to / return from a function |
513 | #[derive (Copy, Clone, Debug, PartialEq, Eq)] |
514 | pub enum TypeKind { |
515 | /// A by-reference arg, EG `&T` |
516 | ByRef, |
517 | /// A by-mutable-reference arg, EG `&mut T` |
518 | ByMutRef, |
519 | /// A by-value arg, EG `T` |
520 | ByValue, |
521 | } |
522 | |
523 | /// Unused, the location of a type for a function argument (import/export, argument/ret) |
524 | #[derive (Copy, Clone, Debug, PartialEq, Eq)] |
525 | pub enum TypeLocation { |
526 | /// An imported argument (JS side type) |
527 | ImportArgument, |
528 | /// An imported return |
529 | ImportRet, |
530 | /// An exported argument (Rust side type) |
531 | ExportArgument, |
532 | /// An exported return |
533 | ExportRet, |
534 | } |
535 | |
536 | /// An enum representing either a literal value (`Lit`) or an expression (`syn::Expr`). |
537 | #[cfg_attr (feature = "extra-traits" , derive(Debug))] |
538 | #[derive (Clone)] |
539 | pub enum LitOrExpr { |
540 | /// Represents an expression that needs to be evaluated before it can be encoded |
541 | Expr(syn::Expr), |
542 | /// Represents a literal string that can be directly encoded. |
543 | Lit(String), |
544 | } |
545 | |
546 | impl Export { |
547 | /// Mangles a rust -> javascript export, so that the created Ident will be unique over function |
548 | /// name and class name, if the function belongs to a javascript class. |
549 | pub(crate) fn rust_symbol(&self) -> Ident { |
550 | let mut generated_name = String::from("__wasm_bindgen_generated" ); |
551 | if let Some(class) = &self.js_class { |
552 | generated_name.push('_' ); |
553 | generated_name.push_str(class); |
554 | } |
555 | generated_name.push('_' ); |
556 | generated_name.push_str(&self.function.name.to_string()); |
557 | Ident::new(&generated_name, Span::call_site()) |
558 | } |
559 | |
560 | /// This is the name of the shim function that gets exported and takes the raw |
561 | /// ABI form of its arguments and converts them back into their normal, |
562 | /// "high level" form before calling the actual function. |
563 | pub(crate) fn export_name(&self) -> String { |
564 | let fn_name = self.function.name.to_string(); |
565 | match &self.js_class { |
566 | Some(class) => shared::struct_function_export_name(class, &fn_name), |
567 | None => shared::free_function_export_name(&fn_name), |
568 | } |
569 | } |
570 | } |
571 | |
572 | impl ImportKind { |
573 | /// Whether this type can be inside an `impl` block. |
574 | pub fn fits_on_impl(&self) -> bool { |
575 | match *self { |
576 | ImportKind::Function(_) => true, |
577 | ImportKind::Static(_) => false, |
578 | ImportKind::String(_) => false, |
579 | ImportKind::Type(_) => false, |
580 | ImportKind::Enum(_) => false, |
581 | } |
582 | } |
583 | } |
584 | |
585 | impl Function { |
586 | /// If the rust object has a `fn xxx(&self) -> MyType` method, get the name for a getter in |
587 | /// javascript (in this case `xxx`, so you can write `val = obj.xxx`) |
588 | pub fn infer_getter_property(&self) -> &str { |
589 | &self.name |
590 | } |
591 | |
592 | /// If the rust object has a `fn set_xxx(&mut self, MyType)` style method, get the name |
593 | /// for a setter in javascript (in this case `xxx`, so you can write `obj.xxx = val`) |
594 | pub fn infer_setter_property(&self) -> Result<String, Diagnostic> { |
595 | let name: String = self.name.to_string(); |
596 | |
597 | // Otherwise we infer names based on the Rust function name. |
598 | if !name.starts_with("set_" ) { |
599 | bail_span!( |
600 | syn::token::Pub(self.name_span), |
601 | "setters must start with `set_`, found: {}" , |
602 | name, |
603 | ); |
604 | } |
605 | Ok(name[4..].to_string()) |
606 | } |
607 | } |
608 | |