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}