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}