ion_proc/class/
property.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7use proc_macro2::{Ident, TokenStream};
8use quote::{format_ident, quote};
9use syn::{ImplItemConst, Result, Type};
10
11use crate::attribute::ParseAttribute as _;
12use crate::attribute::name::Name;
13use crate::attribute::property::PropertyAttribute;
14use crate::utils::path_ends_with;
15
16#[derive(Clone, Debug)]
17pub(super) enum PropertyType {
18	Int32,
19	Double,
20	String,
21}
22
23#[derive(Clone)]
24pub(super) struct Property {
25	pub(super) ty: PropertyType,
26	pub(super) ident: Ident,
27	pub(super) names: Vec<Name>,
28}
29
30impl Property {
31	pub(super) fn from_const(r#const: &mut ImplItemConst) -> Result<Option<(Property, bool)>> {
32		let mut names = Vec::new();
33
34		let attribute = PropertyAttribute::from_attributes("ion", &mut r#const.attrs, ())?;
35
36		let PropertyAttribute { name, alias, skip, r#static } = attribute;
37		for alias in alias {
38			names.push(Name::String(alias));
39		}
40
41		r#const.attrs.clear();
42		if skip {
43			return Ok(None);
44		}
45
46		let ident = r#const.ident.clone();
47
48		match name {
49			Some(name) => names.insert(0, name),
50			None => names.insert(0, Name::from_string(ident.to_string(), ident.span())),
51		}
52
53		match &r#const.ty {
54			Type::Path(ty) => {
55				if path_ends_with(&ty.path, "i32") {
56					Ok(Some((Property { ty: PropertyType::Int32, ident, names }, r#static)))
57				} else if path_ends_with(&ty.path, "f64") {
58					Ok(Some((Property { ty: PropertyType::Double, ident, names }, r#static)))
59				} else {
60					Ok(None)
61				}
62			}
63			Type::Reference(re) => {
64				if let Type::Path(ty) = &*re.elem
65					&& path_ends_with(&ty.path, "str")
66				{
67					return Ok(Some((Property { ty: PropertyType::String, ident, names }, r#static)));
68				}
69				Ok(None)
70			}
71			_ => Ok(None),
72		}
73	}
74
75	pub(super) fn to_specs(&self, ion: &TokenStream, class: &Ident) -> Vec<TokenStream> {
76		let ident = &self.ident;
77
78		self.names
79			.iter()
80			.map(|name| {
81				let mut function_ident = format_ident!("create_property_spec");
82
83				let (key, flags) = name.to_property_spec(ion, &mut function_ident);
84
85				function_ident = match self.ty {
86					PropertyType::Int32 => format_ident!("{}_int", function_ident),
87					PropertyType::Double => format_ident!("{}_double", function_ident),
88					PropertyType::String => format_ident!("{}_string", function_ident),
89				};
90
91				quote!(#ion::spec::#function_ident(#key, #class::#ident, #flags))
92			})
93			.collect()
94	}
95}