rune_macros/
hash.rs
1use core::mem::take;
2
3use rune_core::hash::Hash;
4use rune_core::item::{ComponentRef, ItemBuf};
5use syn::parse::{Parse, ParseStream};
6
7use crate::context::Context;
8
9pub(super) struct Arguments {
10 path: syn::Path,
11 associated: Option<(syn::Token![.], syn::Ident)>,
12}
13
14impl Arguments {
15 pub(super) fn new(path: syn::Path) -> Self {
16 Self {
17 path,
18 associated: None,
19 }
20 }
21
22 pub(crate) fn build_type_item(&self, cx: &Context) -> Result<syn::ExprArray, ()> {
24 match crate::item::build_item(&self.path) {
25 Ok(type_item) => Ok(type_item),
26 Err(error) => {
27 cx.error(error);
28 Err(())
29 }
30 }
31 }
32
33 pub(crate) fn build_type_hash(&self, cx: &Context) -> Result<Hash, ()> {
35 self.build_type_hash_with_inner(cx, None)
36 }
37
38 pub(crate) fn build_type_hash_with(&self, cx: &Context, extra: &str) -> Result<Hash, ()> {
40 self.build_type_hash_with_inner(cx, Some(extra))
41 }
42
43 fn build_type_hash_with_inner(&self, cx: &Context, extra: Option<&str>) -> Result<Hash, ()> {
44 let mut buf = ItemBuf::new();
46 let mut first = self.path.leading_colon.is_some();
47
48 for s in &self.path.segments {
49 let ident = s.ident.to_string();
50
51 let c = if take(&mut first) {
52 ComponentRef::Crate(&ident)
53 } else {
54 ComponentRef::Str(&ident)
55 };
56
57 if let Err(error) = buf.push(c) {
58 cx.error(syn::Error::new_spanned(s, error));
59 return Err(());
60 }
61
62 match &s.arguments {
63 syn::PathArguments::None => {}
64 syn::PathArguments::AngleBracketed(generics) => {
65 cx.error(syn::Error::new_spanned(
66 generics,
67 "Generic arguments are not supported",
68 ));
69 }
70 syn::PathArguments::Parenthesized(generics) => {
71 cx.error(syn::Error::new_spanned(
72 generics,
73 "Generic arguments are not supported",
74 ));
75 }
76 }
77 }
78
79 if let Some(extra) = extra {
80 if let Err(error) = buf.push(ComponentRef::Str(extra)) {
81 cx.error(syn::Error::new_spanned(&self.path, error));
82 return Err(());
83 }
84 }
85
86 let base = Hash::type_hash(&buf);
87
88 let hash = if let Some((_, associated)) = &self.associated {
89 let name = associated.to_string();
90 Hash::associated_function(base, name.as_str())
91 } else {
92 base
93 };
94
95 Ok(hash)
96 }
97}
98
99impl Parse for Arguments {
100 fn parse(input: ParseStream) -> syn::Result<Self> {
101 let path = input.parse()?;
102
103 let ident = if let Some(colon) = input.parse::<Option<syn::Token![.]>>()? {
104 Some((colon, input.parse()?))
105 } else {
106 None
107 };
108
109 Ok(Self {
110 path,
111 associated: ident,
112 })
113 }
114}