common_macro/row/
attribute.rs1use std::collections::HashMap;
16
17use once_cell::sync::Lazy;
18use syn::meta::ParseNestedMeta;
19use syn::spanned::Spanned;
20use syn::{Attribute, LitStr, Meta, Result};
21
22use crate::row::utils::{
23 ColumnDataTypeWithExtension, SemanticType, column_data_type_from_str, semantic_type_from_str,
24};
25use crate::row::{
26 META_KEY_COL, META_KEY_DATATYPE, META_KEY_NAME, META_KEY_SEMANTIC, META_KEY_SKIP,
27};
28
29#[derive(Default)]
31pub(crate) struct ColumnAttribute {
32 pub(crate) name: Option<String>,
34 pub(crate) datatype: Option<ColumnDataTypeWithExtension>,
36 pub(crate) semantic_type: SemanticType,
38 pub(crate) skip: bool,
40}
41
42pub(crate) fn find_column_attribute(attrs: &[Attribute]) -> Option<&Attribute> {
44 attrs
45 .iter()
46 .find(|attr| matches!(&attr.meta, Meta::List(list) if list.path.is_ident(META_KEY_COL)))
47}
48
49pub(crate) fn parse_column_attribute(attr: &Attribute) -> Result<ColumnAttribute> {
51 match &attr.meta {
52 Meta::List(list) if list.path.is_ident(META_KEY_COL) => {
53 let mut attribute = ColumnAttribute::default();
54 list.parse_nested_meta(|meta| parse_column_attribute_field(&meta, &mut attribute))?;
55 Ok(attribute)
56 }
57 _ => Err(syn::Error::new(
58 attr.span(),
59 format!(
60 "expected `{META_KEY_COL}({META_KEY_NAME} = \"...\", {META_KEY_DATATYPE} = \"...\", {META_KEY_SEMANTIC} = \"...\")`"
61 ),
62 )),
63 }
64}
65
66type ParseColumnAttributeField = fn(&ParseNestedMeta, &mut ColumnAttribute) -> Result<()>;
67
68static PARSE_COLUMN_ATTRIBUTE_FIELDS: Lazy<HashMap<&str, ParseColumnAttributeField>> =
69 Lazy::new(|| {
70 HashMap::from([
71 (META_KEY_NAME, parse_name_field as _),
72 (META_KEY_DATATYPE, parse_datatype_field as _),
73 (META_KEY_SEMANTIC, parse_semantic_field as _),
74 (META_KEY_SKIP, parse_skip_field as _),
75 ])
76 });
77
78fn parse_name_field(meta: &ParseNestedMeta<'_>, attribute: &mut ColumnAttribute) -> Result<()> {
79 let value = meta.value()?;
80 let s: LitStr = value.parse()?;
81 attribute.name = Some(s.value());
82 Ok(())
83}
84
85fn parse_datatype_field(meta: &ParseNestedMeta<'_>, attribute: &mut ColumnAttribute) -> Result<()> {
86 let value = meta.value()?;
87 let s: LitStr = value.parse()?;
88 let ident = s.value();
89 let Some(value) = column_data_type_from_str(&ident) else {
90 return Err(meta.error(format!("unexpected {META_KEY_DATATYPE}: {ident}")));
91 };
92 attribute.datatype = Some(value);
93 Ok(())
94}
95
96fn parse_semantic_field(meta: &ParseNestedMeta<'_>, attribute: &mut ColumnAttribute) -> Result<()> {
97 let value = meta.value()?;
98 let s: LitStr = value.parse()?;
99 let ident = s.value();
100 let Some(value) = semantic_type_from_str(&ident) else {
101 return Err(meta.error(format!("unexpected {META_KEY_SEMANTIC}: {ident}")));
102 };
103 attribute.semantic_type = value;
104 Ok(())
105}
106
107fn parse_skip_field(_: &ParseNestedMeta<'_>, attribute: &mut ColumnAttribute) -> Result<()> {
108 attribute.skip = true;
109 Ok(())
110}
111
112fn parse_column_attribute_field(
113 meta: &ParseNestedMeta<'_>,
114 attribute: &mut ColumnAttribute,
115) -> Result<()> {
116 let Some(ident) = meta.path.get_ident() else {
117 return Err(meta.error(format!("expected `{META_KEY_COL}({META_KEY_NAME} = \"...\", {META_KEY_DATATYPE} = \"...\", {META_KEY_SEMANTIC} = \"...\")`")));
118 };
119 let Some(parse_column_attribute) =
120 PARSE_COLUMN_ATTRIBUTE_FIELDS.get(ident.to_string().as_str())
121 else {
122 return Err(meta.error(format!("unexpected attribute: {ident}")));
123 };
124
125 parse_column_attribute(meta, attribute)
126}