rune_core/
protocol.rs

1use core::cmp;
2use core::fmt;
3use core::hash::Hasher;
4
5#[cfg(feature = "alloc")]
6use crate::alloc;
7use crate::hash::{Hash, ToTypeHash};
8use crate::item::ItemBuf;
9
10/// A built in instance function.
11#[derive(Debug)]
12#[non_exhaustive]
13pub struct Protocol {
14    /// The name of the builtin function.
15    pub name: &'static str,
16    /// If this protocol defines an associated method, this is the name of that
17    /// method.
18    pub method: Option<&'static str>,
19    /// The hash of the builtin function.
20    pub hash: Hash,
21    /// Representative expression for the protocol.
22    ///
23    /// If no such expression is present, then it means that its an internal
24    /// protocol.
25    #[cfg(feature = "doc")]
26    #[doc(hidden)]
27    pub repr: Option<&'static str>,
28    /// Documentation for protocol.
29    #[cfg(feature = "doc")]
30    #[doc(hidden)]
31    pub doc: &'static [&'static str],
32}
33
34impl ToTypeHash for &Protocol {
35    #[inline]
36    fn to_type_hash(&self) -> Hash {
37        self.hash
38    }
39
40    #[inline]
41    #[cfg(feature = "alloc")]
42    fn to_item(&self) -> alloc::Result<Option<ItemBuf>> {
43        Ok(None)
44    }
45}
46
47impl fmt::Display for Protocol {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        write!(f, "{}", self.name)
50    }
51}
52
53impl cmp::PartialEq for Protocol {
54    #[inline]
55    fn eq(&self, other: &Self) -> bool {
56        self.hash.eq(&other.hash)
57    }
58}
59
60impl cmp::Eq for Protocol {}
61
62impl core::hash::Hash for Protocol {
63    #[inline]
64    fn hash<H: Hasher>(&self, state: &mut H) {
65        self.hash.hash(state)
66    }
67}
68
69macro_rules! maybe {
70    ($tt:tt $($rest:tt)*) => { Some($tt $($rest)*) };
71    () => { None };
72}
73
74macro_rules! define {
75    (
76        $(
77            $(#[$($meta:meta)*])*
78            $vis:vis const $ident:ident: Protocol = Protocol {
79                $(method: $method:expr,)?
80                hash: $hash:expr,
81                $(repr: $repr:expr,)?
82                $(#[doc = $doc:expr])*
83            };
84        )*
85    ) => {
86        impl Protocol {
87            $(
88                $(#[$($meta)*])*
89                $vis const $ident: Protocol = Protocol {
90                    name: stringify!($ident),
91                    method: maybe!($($method)*),
92                    hash: Hash($hash),
93                    #[cfg(feature = "doc")]
94                    repr: maybe!($($repr)*),
95                    #[cfg(feature = "doc")]
96                    doc: &[$($doc),*],
97                };
98            )*
99
100            /// Look up protocol for the given hash.
101            pub fn from_hash(hash: Hash) -> Option<Self> {
102                match hash {
103                    $(
104                        Hash($hash) => {
105                            Some(Self::$ident)
106                        },
107                    )*
108                    _ => None,
109                }
110            }
111        }
112
113        #[test]
114        fn ensure_unique_hashes() {
115            let mut map = ::rust_std::collections::HashMap::<Hash, &'static str>::new();
116
117            $(
118                if let Some(ident) = map.insert(Hash($hash), stringify!($ident)) {
119                    panic!("Trying to define protocol hash `{}` for `{}`, but it's already defined for {ident}", $hash, stringify!($ident));
120                }
121            )*
122        }
123    }
124}
125
126define! {
127    /// The function to access a field.
128    pub const GET: Protocol = Protocol {
129        hash: 0x504007af1a8485a4u64,
130        repr: "let $out = $value",
131        /// Allows a get operation to work.
132    };
133
134    /// The function to set a field.
135    pub const SET: Protocol = Protocol {
136        hash: 0x7d13d47fd8efef5au64,
137        repr: "$value = $input",
138        /// Allows a set operation to work.
139    };
140
141    /// The function to access an index.
142    pub const INDEX_GET: Protocol = Protocol {
143        hash: 0xadb5b27e2a4d2decu64,
144        repr: "let $out = $value[index]",
145        /// Allows an indexing get operation to work.
146    };
147
148    /// The function to set an index.
149    pub const INDEX_SET: Protocol = Protocol {
150        hash: 0x162943f7bd03ad36u64,
151        repr: "$value[index] = $input",
152        /// Allows an indexing set operation to work.
153    };
154
155    /// Check two types for partial equality.
156    pub const PARTIAL_EQ: Protocol = Protocol {
157        method: "eq",
158        hash: 0x4b6bc4701445e318u64,
159        repr: "if $value == b { }",
160        /// Allows for partial equality operations to work.
161    };
162
163    /// Check two types for total equality.
164    pub const EQ: Protocol = Protocol {
165        hash: 0x418f5becbf885806u64,
166        repr: "if $value == b { }",
167        /// Allows an equality operation to work.
168    };
169
170    /// Perform an partial comparison between two values.
171    pub const PARTIAL_CMP: Protocol = Protocol {
172        method: "partial_cmp",
173        hash: 0x8d4430991253343cu64,
174        repr: "if $value < b { }",
175        /// Allows for partial ordering to work. This is used as the basis for all internal comparisons.
176    };
177
178    /// The protocol behind the `>` operator.
179    pub const GT: Protocol = Protocol {
180        method: "gt",
181        hash: 0x29d9486ee6aa98ddu64,
182        repr: "if $a > $b { }",
183        /// The protocol behind the `>` operator.
184    };
185
186    /// The protocol behind the `>=` operator.
187    pub const GE: Protocol = Protocol {
188        method: "ge",
189        hash: 0x2bb35b8f086340bu64,
190        repr: "if $a >= $b { }",
191        /// The protocol behind the `>=` operator.
192    };
193
194    /// The protocol behind the `>` operator.
195    pub const LT: Protocol = Protocol {
196        method: "lt",
197        hash: 0x82cb74423db0a3b6u64,
198        repr: "if $a < $b { }",
199        /// The protocol behind the `<` operator.
200    };
201
202    /// The protocol behind the `<=` operator.
203    pub const LE: Protocol = Protocol {
204        method: "le",
205        hash: 0xcba7d52a7ca8c617u64,
206        repr: "if $a <= $b { }",
207        /// The protocol behind the `<=` operator.
208    };
209
210    pub const MAX: Protocol = Protocol {
211        method: "max",
212        hash: 0xca63c8386a41c812u64,
213        repr: "$a.max($b)",
214        /// The implementation protocol for the `PartialOrd::max` method.
215    };
216
217    pub const MIN: Protocol = Protocol {
218        method: "min",
219        hash: 0x454f2aabc9d16509u64,
220        repr: "$a.min($b)",
221        /// The implementation protocol for the `PartialOrd::min` method.
222    };
223
224    /// Perform an total comparison between two values.
225    pub const CMP: Protocol = Protocol {
226        method: "cmp",
227        hash: 0x240f1b75466cd1a3u64,
228        repr: "if $value < b { }",
229        /// Allows for total ordering to work.
230    };
231
232    /// The function to implement for the addition operation.
233    pub const ADD: Protocol = Protocol {
234        hash: 0xe4ecf51fa0bf1076u64,
235        repr: "let $out = $value + $b",
236        /// Allows the `+` operator to apply to values of this type, where the current type is the left-hand side.
237    };
238
239    /// The function to implement for the addition assign operation.
240    pub const ADD_ASSIGN: Protocol = Protocol {
241        hash: 0x42451ccb0a2071a9u64,
242        repr: "$value += $b",
243        /// Allows the `+=` operator to apply to values of this type, where the current type is the left-hand side.
244    };
245
246    /// The function to implement for the subtraction operation.
247    pub const SUB: Protocol = Protocol {
248        hash: 0x6fa86a5f18d0bf71u64,
249        repr: "let $out = $value - $b",
250        /// Allows the `-` operator to apply to values of this type, where the current type is the left-hand side.
251    };
252
253    /// The function to implement for the subtraction assign operation.
254    pub const SUB_ASSIGN: Protocol = Protocol {
255        hash: 0x5939bb56a1415284u64,
256        repr: "$value -= $b",
257        /// Allows the `-=` operator to apply to values of this type, where the current type is the left-hand side.
258    };
259
260    /// The function to implement for the multiply operation.
261    pub const MUL: Protocol = Protocol {
262        hash: 0xb09e99dc94091d1cu64,
263        repr: "let $out = $value * $b",
264        /// Allows the `*` operator to apply to values of this type, where the current type is the left-hand side.
265    };
266
267    /// The function to implement for the multiply assign operation.
268    pub const MUL_ASSIGN: Protocol = Protocol {
269        hash: 0x29a54b727f980ebfu64,
270        repr: "$value *= $b",
271        /// Allows the `*=` operator to apply to values of this type, where the current type is the left-hand side.
272    };
273
274    /// The function to implement for the division operation.
275    pub const DIV: Protocol = Protocol {
276        hash: 0xf26d6eea1afca6e8u64,
277        repr: "let $out = $value / $b",
278        /// Allows the `/` operator to apply to values of this type, where the current type is the left-hand side.
279    };
280
281    /// The function to implement for the division assign operation.
282    pub const DIV_ASSIGN: Protocol = Protocol {
283        hash: 0x4dd087a8281c04e6u64,
284        repr: "$value /= $b",
285        /// Allows the `/=` operator to apply to values of this type, where the current type is the left-hand side.
286    };
287
288    /// The function to implement for the remainder operation.
289    pub const REM: Protocol = Protocol {
290        hash: 0x5c6293639c74e671u64,
291        repr: "let $out = $value % $b",
292        /// Allows the `%` operator to apply to values of this type, where the current type is the left-hand side.
293    };
294
295    /// The function to implement for the remainder assign operation.
296    pub const REM_ASSIGN: Protocol = Protocol {
297        hash: 0x3a8695980e77baf4u64,
298        repr: "$value %= $b",
299        /// Allows the `%=` operator to apply to values of this type, where the current type is the left-hand side.
300    };
301
302    /// The function to implement for the bitwise and operation.
303    pub const BIT_AND: Protocol = Protocol {
304        hash: 0x0e11f20d940eebe8u64,
305        repr: "let $out = $value & $b",
306        /// Allows the `&` operator to apply to values of this type, where the current type is the left-hand side.
307    };
308
309    /// The function to implement for the bitwise and assign operation.
310    pub const BIT_AND_ASSIGN: Protocol = Protocol {
311        hash: 0x95cb1ba235dfb5ecu64,
312        repr: "$value &= $b",
313        /// Allows the `&=` operator to apply to values of this type, where the current type is the left-hand side.
314    };
315
316    /// The function to implement for the bitwise xor operation.
317    pub const BIT_XOR: Protocol = Protocol {
318        hash: 0xa3099c54e1de4cbfu64,
319        repr: "let $out = $value ^ $b",
320        /// Allows the `^` operator to apply to values of this type, where the current type is the left-hand side.
321    };
322
323    /// The function to implement for the bitwise xor assign operation.
324    pub const BIT_XOR_ASSIGN: Protocol = Protocol {
325        hash: 0x01fa9706738f9867u64,
326        repr: "$value ^= $b",
327        /// Allows the `^=` operator to apply to values of this type, where the current type is the left-hand side.
328    };
329
330    /// The function to implement for the bitwise or operation.
331    pub const BIT_OR: Protocol = Protocol {
332        hash: 0x05010afceb4a03d0u64,
333        repr: "let $out = $value | $b",
334        /// Allows the `|` operator to apply to values of this type, where the current type is the left-hand side.
335    };
336
337    /// The function to implement for the bitwise xor assign operation.
338    pub const BIT_OR_ASSIGN: Protocol = Protocol {
339        hash: 0x606d79ff1750a7ecu64,
340        repr: "$value |= $b",
341        /// Allows the `|=` operator to apply to values of this type, where the current type is the left-hand side.
342    };
343
344    /// The function to implement for the bitwise shift left operation.
345    pub const SHL: Protocol = Protocol {
346        hash: 0x6845f7d0cc9e002du64,
347        repr: "let $out = $value << $b",
348        /// Allows the `<<` operator to apply to values of this type, where the current type is the left-hand side.
349    };
350
351    /// The function to implement for the bitwise shift left assign operation.
352    pub const SHL_ASSIGN: Protocol = Protocol {
353        hash: 0xdc4702d0307ba27bu64,
354        repr: "$value <<= $b",
355        /// Allows the `<<=` operator to apply to values of this type, where the current type is the left-hand side.
356    };
357
358    /// The function to implement for the bitwise shift right operation.
359    pub const SHR: Protocol = Protocol {
360        hash: 0x6b485e8e6e58fbc8u64,
361        repr: "let $out = $value >> $b",
362        /// Allows the `>>` operator to apply to values of this type, where the current type is the left-hand side.
363    };
364
365    /// The function to implement for the bitwise shift right assign operation.
366    pub const SHR_ASSIGN: Protocol = Protocol {
367        hash: 0x61ff7c46ff00e74au64,
368        repr: "$value >>= $b",
369        /// Allows the `>>=` operator to apply to values of this type, where the current type is the left-hand side.
370    };
371
372    /// Protocol function used by template strings.
373    pub const DISPLAY_FMT: Protocol = Protocol {
374        hash: 0x811b62957ea9d9f9u64,
375        repr: "format!(\"{}\", $value)",
376        /// Allows the value to be display printed.
377    };
378
379    /// Protocol function used by custom debug impls.
380    pub const DEBUG_FMT: Protocol = Protocol {
381        hash: 0x4064e3867aaa0717u64,
382        repr: "format!(\"{:?}\", $value)",
383        /// Allows the value to be debug printed.
384    };
385
386    /// Function used to convert an argument into an iterator.
387    pub const INTO_ITER: Protocol = Protocol {
388        hash: 0x15a85c8d774b4065u64,
389        repr: "for item in $value { }",
390        /// Allows the value to be converted into an iterator in a for-loop.
391    };
392
393    /// The function to call to continue iteration.
394    pub const NEXT: Protocol = Protocol {
395        method: "next",
396        hash: 0xc3cde069de2ba320u64,
397        repr: "let $out = $value.next()",
398        /// Allows iteration to be advanced for the type, this is used for iterators.
399    };
400
401    /// The function to call to continue iteration at the nth element.
402    pub const NTH: Protocol = Protocol {
403        method: "nth",
404        hash: 0x6704550736c82a58u64,
405        repr: "let $out = $value.nth(index)",
406        /// Allows iteration to be advanced for the type to the nth element, this is used for iterators.
407    };
408
409    /// The function to call to continue iteration at the nth element form the back.
410    pub const NTH_BACK: Protocol = Protocol {
411        method: "nth_back",
412        hash: 0x4885ca2fd53a08c8u64,
413        /// Allows iteration to be advanced for the type to the nth element from the back, this is used for iterators.
414    };
415
416    /// Protocol used when getting the size hint of an iterator.
417    pub const SIZE_HINT: Protocol = Protocol {
418        method: "size_hint",
419        hash: 0x1a7b50baabc6e094u64,
420        repr: "let $out = $value.size_hint()",
421        /// Get the size hint of an iterator.
422    };
423
424    /// Protocol used when getting the exact length of an iterator.
425    pub const LEN: Protocol = Protocol {
426        method: "len",
427        hash: 0x52dd3b9489d39c42u64,
428        repr: "let $out = $value.len()",
429        /// Get the length of an iterator.
430    };
431
432    /// Protocol used when cloning a value.
433    pub const NEXT_BACK: Protocol = Protocol {
434        method: "next_back",
435        hash: 0x91149fef42c0a8aeu64,
436        repr: "let $out = $value.next_back()",
437        /// Get the next value from the back of the iterator.
438    };
439
440    /// Function used to convert an argument into a future.
441    ///
442    /// Signature: `fn(Value) -> Future`.
443    pub const INTO_FUTURE: Protocol = Protocol {
444        hash: 0x596e6428deabfda2u64,
445        repr: "$value.await",
446        /// This protocol allows the type to be converted into a future by awaiting them.
447    };
448
449    /// Coerce a value into a type name. This is stored as a constant.
450    pub const INTO_TYPE_NAME: Protocol = Protocol {
451        hash: 0xbffd08b816c24682u64,
452        /// This protocol allows the type to be converted into a string which represents the type name."
453    };
454
455    /// Function used to test if a value is a specific variant.
456    ///
457    /// Signature: `fn(self, Hash) -> bool`.
458    pub const IS_VARIANT: Protocol = Protocol {
459        hash: 0xc030d82bbd4dabe8u64,
460        /// Test if the provided argument is a variant.
461    };
462
463    /// Function used for the question mark operation.
464    ///
465    /// Signature: `fn(self) -> Result`.
466    ///
467    /// Note that it uses the `Result` like [`Try`] uses [`ControlFlow`] i.e.,
468    /// for `Result::<T, E>` it should return `Result<T, Result<(), E>>`
469    ///
470    /// [`Try`]: core::ops::Try
471    /// [`ControlFlow`]: core::ops::ControlFlow
472    pub const TRY: Protocol = Protocol {
473        hash: 0x5da1a80787003354u64,
474        repr: "value?",
475        /// Allows the `?` operator to apply to values of this type.
476    };
477
478    /// Protocol used when calculating a hash.
479    pub const HASH: Protocol = Protocol {
480        hash: 0xf6cf2d9f416cef08u64,
481        repr: "let $out = hash($value)",
482        /// Hash a value.
483    };
484
485    /// Protocol used when cloning a value.
486    pub const CLONE: Protocol = Protocol {
487        method: "clone",
488        hash: 0x2af2c875e36971eu64,
489        repr: "let $out = clone($value)",
490        /// Clone a value.
491    };
492}