ink_ir/ir/event/
signature_topic.rs

1// Copyright (C) Use Ink (UK) Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use impl_serde::serialize as serde_hex;
16use syn::spanned::Spanned;
17
18use crate::ast;
19
20/// The signature topic argument of an event variant.
21///
22/// Used as part of `ink::event` macro.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub struct SignatureTopicArg {
25    topic: [u8; 32],
26}
27
28impl SignatureTopicArg {
29    pub fn signature_topic(&self) -> [u8; 32] {
30        self.topic
31    }
32}
33
34impl From<&[u8; 32]> for SignatureTopicArg {
35    fn from(value: &[u8; 32]) -> Self {
36        Self { topic: *value }
37    }
38}
39
40impl TryFrom<&syn::Lit> for SignatureTopicArg {
41    type Error = syn::Error;
42
43    fn try_from(lit: &syn::Lit) -> Result<Self, Self::Error> {
44        if let syn::Lit::Str(s) = lit {
45            let bytes: [u8; 32] = serde_hex::from_hex(&s.value())
46                    .map_err(|_| {
47                        format_err_spanned!(
48                            lit,
49                            "`signature_topic` has invalid hex string",
50                        )
51                    })?
52                    .try_into()
53                    .map_err(|e: Vec<u8>| {
54                        format_err_spanned!(
55                            lit,
56                            "`signature_topic` is expected to be 32-byte hex string. Found {} bytes",
57                            e.len()
58                        )
59                    })?;
60
61            Ok(Self { topic: bytes })
62        } else {
63            Err(format_err_spanned!(
64                lit,
65                "Expected string literal argument for the `signature_topic`"
66            ))
67        }
68    }
69}
70
71impl TryFrom<&ast::MetaValue> for SignatureTopicArg {
72    type Error = syn::Error;
73
74    fn try_from(value: &ast::MetaValue) -> Result<Self, Self::Error> {
75        if let ast::MetaValue::Lit(lit) = value {
76            Self::try_from(lit)
77        } else {
78            Err(format_err_spanned!(
79                value,
80                "Expected string argument for the `signature_topic`"
81            ))
82        }
83    }
84}
85
86impl TryFrom<ast::AttributeArgs> for Option<SignatureTopicArg> {
87    type Error = syn::Error;
88
89    fn try_from(args: ast::AttributeArgs) -> Result<Self, Self::Error> {
90        let mut signature_topic: Option<SignatureTopicArg> = None;
91        for arg in args.into_iter() {
92            if arg.name().is_ident("hash") {
93                if signature_topic.is_some() {
94                    return Err(format_err!(
95                        arg.span(),
96                        "encountered duplicate ink! event configuration argument"
97                    ));
98                }
99                signature_topic =
100                    arg.value().map(SignatureTopicArg::try_from).transpose()?;
101            } else {
102                return Err(format_err_spanned!(
103                    arg,
104                    "encountered unknown or unsupported ink! event item configuration argument",
105                ));
106            }
107        }
108        Ok(signature_topic)
109    }
110}
111
112impl TryFrom<&syn::MetaNameValue> for SignatureTopicArg {
113    type Error = syn::Error;
114
115    fn try_from(nv: &syn::MetaNameValue) -> Result<Self, Self::Error> {
116        if nv.path.is_ident("signature_topic") {
117            if let syn::Expr::Lit(lit_expr) = &nv.value {
118                Self::try_from(&lit_expr.lit)
119            } else {
120                Err(format_err_spanned!(&nv.value, "Expected literal argument"))
121            }
122        } else {
123            Err(format_err_spanned!(nv, "Expected `signature_topic` ident"))
124        }
125    }
126}