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