1use core::{
2 fmt,
3 hash::{Hash, Hasher},
4};
5
6pub use miden_core::Felt;
7
8use super::{AttrPrinter, parse::ParserExt};
9use crate::{
10 Type,
11 attributes::{AttrParser, InferAttributeType, IntegerLikeAttr},
12 derive::DialectAttribute,
13 dialects::builtin::BuiltinDialect,
14 formatter::PrettyPrint,
15};
16
17#[derive(DialectAttribute, Debug, Copy, Clone)]
18#[attribute(name = "number", dialect = BuiltinDialect, implements(AttrPrinter, IntegerLikeAttr))]
19pub enum Immediate {
20 I1(bool),
21 U8(u8),
22 I8(i8),
23 U16(u16),
24 I16(i16),
25 U32(u32),
26 I32(i32),
27 U64(u64),
28 I64(i64),
29 U128(u128),
30 I128(i128),
31 F64(f64),
32 Felt(Felt),
33}
34
35impl Default for Immediate {
36 fn default() -> Self {
37 Self::I32(0)
39 }
40}
41
42impl IntegerLikeAttr for ImmediateAttr {
43 #[inline(always)]
44 fn as_immediate(&self) -> Immediate {
45 self.value
46 }
47
48 #[inline(always)]
49 fn set_from_immediate_lossy(&mut self, value: Immediate) {
50 self.value = value;
51 }
52}
53
54impl AttrPrinter for ImmediateAttr {
55 fn print(&self, printer: &mut super::print::AsmPrinter<'_>) {
56 match self.value {
57 Immediate::F64(_) => todo!("IR assembly support for floats"),
58 value => {
59 printer.print_decimal_integer(value);
60 }
61 }
62 }
63}
64
65impl AttrParser for ImmediateAttr {
66 fn parse(
67 parser: &mut dyn super::parse::Parser<'_>,
68 ) -> super::parse::ParseResult<crate::AttributeRef> {
69 use crate::parse::Token;
70
71 let imm = if parser.token_stream_mut().is_next(|tok| matches!(tok, Token::Minus)) {
72 Immediate::I128(parser.parse_decimal_integer::<i128>()?.into_inner())
73 } else {
74 Immediate::U128(parser.parse_decimal_integer::<u128>()?.into_inner())
75 };
76
77 Ok(parser.context_rc().create_attribute::<ImmediateAttr, _>(imm))
78 }
79}
80
81impl InferAttributeType for ImmediateAttr {
82 fn infer_type() -> Type {
83 Type::Unknown
85 }
86
87 #[inline]
88 fn infer_type_from_value(value: &<Self as crate::AttributeRegistration>::Value) -> Type {
89 value.ty()
90 }
91}
92
93impl Immediate {
94 pub fn ty(&self) -> Type {
95 match self {
96 Self::I1(_) => Type::I1,
97 Self::U8(_) => Type::U8,
98 Self::I8(_) => Type::I8,
99 Self::U16(_) => Type::U16,
100 Self::I16(_) => Type::I16,
101 Self::U32(_) => Type::U32,
102 Self::I32(_) => Type::I32,
103 Self::U64(_) => Type::U64,
104 Self::I64(_) => Type::I64,
105 Self::U128(_) => Type::U128,
106 Self::I128(_) => Type::I128,
107 Self::F64(_) => Type::F64,
108 Self::Felt(_) => Type::Felt,
109 }
110 }
111
112 pub fn coerced_to(self, ty: &Type) -> Option<Self> {
117 match ty {
118 Type::I1 => self.as_bool().map(Self::I1),
119 Type::U8 => self.as_u8().map(Self::U8),
120 Type::I8 => self.as_i8().map(Self::I8),
121 Type::U16 => self.as_u16().map(Self::U16),
122 Type::I16 => self.as_i16().map(Self::I16),
123 Type::U32 => self.as_u32().map(Self::U32),
124 Type::I32 => self.as_i32().map(Self::I32),
125 Type::U64 => self.as_u64().map(Self::U64),
126 Type::I64 => self.as_i64().map(Self::I64),
127 Type::U128 => self.as_u128().map(Self::U128),
128 Type::I128 => self.as_i128().map(Self::I128),
129 Type::Felt => self.as_felt().map(Self::Felt),
130 _ => None,
131 }
132 }
133
134 pub fn is_non_negative(&self) -> bool {
136 match self {
137 Self::I1(i) => *i,
138 Self::I8(i) => *i > 0,
139 Self::U8(i) => *i > 0,
140 Self::I16(i) => *i > 0,
141 Self::U16(i) => *i > 0,
142 Self::I32(i) => *i > 0,
143 Self::U32(i) => *i > 0,
144 Self::I64(i) => *i > 0,
145 Self::U64(i) => *i > 0,
146 Self::U128(i) => *i > 0,
147 Self::I128(i) => *i > 0,
148 Self::F64(f) => f.is_sign_positive(),
149 Self::Felt(_) => true,
150 }
151 }
152
153 pub fn is_signed(&self) -> bool {
155 matches!(
156 self,
157 Self::I8(_) | Self::I16(_) | Self::I32(_) | Self::I64(_) | Self::I128(_) | Self::F64(_)
158 )
159 }
160
161 pub fn is_unsigned(&self) -> bool {
163 matches!(
164 self,
165 Self::I1(_)
166 | Self::U8(_)
167 | Self::U16(_)
168 | Self::U32(_)
169 | Self::U64(_)
170 | Self::U128(_)
171 | Self::Felt(_)
172 )
173 }
174
175 pub fn is_odd(&self) -> Option<bool> {
179 match self {
180 Self::I1(b) => Some(*b),
181 Self::U8(i) => Some((*i).is_multiple_of(2)),
182 Self::I8(i) => Some(*i % 2 == 0),
183 Self::U16(i) => Some((*i).is_multiple_of(2)),
184 Self::I16(i) => Some(*i % 2 == 0),
185 Self::U32(i) => Some((*i).is_multiple_of(2)),
186 Self::I32(i) => Some(*i % 2 == 0),
187 Self::U64(i) => Some((*i).is_multiple_of(2)),
188 Self::I64(i) => Some(*i % 2 == 0),
189 Self::Felt(i) => Some(i.as_canonical_u64().is_multiple_of(2)),
190 Self::U128(i) => Some((*i).is_multiple_of(2)),
191 Self::I128(i) => Some(*i % 2 == 0),
192 Self::F64(_) => None,
193 }
194 }
195
196 pub fn as_bool(self) -> Option<bool> {
200 match self {
201 Self::I1(b) => Some(b),
202 Self::U8(i) => Some(i != 0),
203 Self::I8(i) => Some(i != 0),
204 Self::U16(i) => Some(i != 0),
205 Self::I16(i) => Some(i != 0),
206 Self::U32(i) => Some(i != 0),
207 Self::I32(i) => Some(i != 0),
208 Self::U64(i) => Some(i != 0),
209 Self::I64(i) => Some(i != 0),
210 Self::Felt(i) => Some(i.as_canonical_u64() != 0),
211 Self::U128(i) => Some(i != 0),
212 Self::I128(i) => Some(i != 0),
213 Self::F64(_) => None,
214 }
215 }
216
217 pub fn bitcast_u8(self) -> Option<u8> {
219 match self {
220 Self::I1(b) => Some(b as u8),
221 Self::U8(b) => Some(b),
222 Self::I8(b) => Some(b as u8),
223 Self::U16(b) => u8::try_from(b).ok(),
224 Self::I16(b) => i8::try_from(b).ok().map(|v| v as u8),
225 Self::U32(b) => u8::try_from(b).ok(),
226 Self::I32(b) => i8::try_from(b).ok().map(|v| v as u8),
227 Self::U64(b) => u8::try_from(b).ok(),
228 Self::I64(b) => i8::try_from(b).ok().map(|v| v as u8),
229 Self::Felt(i) => u8::try_from(i.as_canonical_u64()).ok(),
230 Self::U128(b) if b <= (u8::MAX as u128) => Some(b as u8),
231 Self::U128(_) => None,
232 Self::I128(b) if b < (i8::MIN as i128) || b > (i8::MAX as i128) => None,
233 Self::I128(b) => Some(b as u8),
234 Self::F64(f) => FloatToInt::<u8>::to_int(f).ok(),
235 }
236 }
237
238 pub fn bitcast_i8(self) -> Option<i8> {
240 match self {
241 Self::I1(b) => Some(b as i8),
242 Self::U8(b) => Some(b as i8),
243 Self::I8(b) => Some(b),
244 Self::U16(b) => i8::try_from(b as i16).ok(),
245 Self::I16(b) => i8::try_from(b).ok(),
246 Self::U32(b) => i8::try_from(b as i32).ok(),
247 Self::I32(b) => i8::try_from(b).ok(),
248 Self::U64(b) => i8::try_from(b as i64).ok(),
249 Self::I64(b) => i8::try_from(b).ok(),
250 Self::Felt(i) => i8::try_from(i.as_canonical_u64() as i64).ok(),
251 Self::U128(b) if b <= (u8::MAX as u128) => Some(b as u8 as i8),
252 Self::U128(_) => None,
253 Self::I128(b) if b < (i8::MIN as i128) || b > (i8::MAX as i128) => None,
254 Self::I128(b) => Some(b as i8),
255 Self::F64(f) => FloatToInt::<i8>::to_int(f).ok(),
256 }
257 }
258
259 pub fn bitcast_u16(self) -> Option<u16> {
261 match self {
262 Self::I1(b) => Some(b as u16),
263 Self::U8(b) => Some(b as u16),
264 Self::I8(b) => Some(b as u16),
265 Self::U16(b) => Some(b),
266 Self::I16(b) => Some(b as u16),
267 Self::U32(b) => u16::try_from(b).ok(),
268 Self::I32(b) => i16::try_from(b).ok().map(|v| v as u16),
269 Self::U64(b) => u16::try_from(b).ok(),
270 Self::I64(b) => i16::try_from(b).ok().map(|v| v as u16),
271 Self::Felt(i) => u16::try_from(i.as_canonical_u64()).ok(),
272 Self::U128(b) if b <= (u16::MAX as u128) => Some(b as u16),
273 Self::U128(_) => None,
274 Self::I128(b) if b < (i16::MIN as i128) || b > (i16::MAX as i128) => None,
275 Self::I128(b) => Some(b as u16),
276 Self::F64(f) => FloatToInt::<u16>::to_int(f).ok(),
277 }
278 }
279
280 pub fn bitcast_i16(self) -> Option<i16> {
282 match self {
283 Self::I1(b) => Some(b as i16),
284 Self::U8(b) => Some(b as i16),
285 Self::I8(b) => Some(b as i16),
286 Self::U16(b) => Some(b as i16),
287 Self::I16(b) => Some(b),
288 Self::U32(b) => u16::try_from(b).ok().map(|v| v as i16),
289 Self::I32(b) => i16::try_from(b).ok(),
290 Self::U64(b) => u16::try_from(b).ok().map(|v| v as i16),
291 Self::I64(b) => i16::try_from(b).ok(),
292 Self::Felt(i) => u16::try_from(i.as_canonical_u64()).ok().map(|v| v as i16),
293 Self::U128(b) if b <= (u16::MAX as u128) => Some(b as i16),
294 Self::U128(_) => None,
295 Self::I128(b) if b < (i16::MIN as i128) || b > (i16::MAX as i128) => None,
296 Self::I128(b) => Some(b as i16),
297 Self::F64(f) => FloatToInt::<i16>::to_int(f).ok(),
298 }
299 }
300
301 pub fn bitcast_u32(self) -> Option<u32> {
303 match self {
304 Self::I1(b) => Some(b as u32),
305 Self::U8(b) => Some(b as u32),
306 Self::I8(b) => Some(b as u32),
307 Self::U16(b) => Some(b as u32),
308 Self::I16(b) => Some(b as u32),
309 Self::U32(b) => Some(b),
310 Self::I32(b) => Some(b as u32),
311 Self::U64(b) => u32::try_from(b).ok(),
312 Self::I64(b) => i32::try_from(b).ok().map(|v| v as u32),
313 Self::Felt(i) => u32::try_from(i.as_canonical_u64()).ok(),
314 Self::U128(b) if b <= (u32::MAX as u128) => Some(b as u32),
315 Self::U128(_) => None,
316 Self::I128(b) if b < (i32::MIN as i128) || b > (i32::MAX as i128) => None,
317 Self::I128(b) => Some(b as u32),
318 Self::F64(f) => FloatToInt::<u32>::to_int(f).ok(),
319 }
320 }
321
322 pub fn bitcast_i32(self) -> Option<i32> {
324 match self {
325 Self::I1(b) => Some(b as i32),
326 Self::U8(b) => Some(b as i32),
327 Self::I8(b) => Some(b as i32),
328 Self::U16(b) => Some(b as i32),
329 Self::I16(b) => Some(b as i32),
330 Self::U32(b) => Some(b as i32),
331 Self::I32(b) => Some(b),
332 Self::U64(b) => u32::try_from(b).ok().map(|v| v as i32),
333 Self::I64(b) => i32::try_from(b).ok(),
334 Self::Felt(i) => u32::try_from(i.as_canonical_u64()).ok().map(|v| v as i32),
335 Self::U128(b) if b <= (u32::MAX as u128) => Some(b as i32),
336 Self::U128(_) => None,
337 Self::I128(b) if b < (i32::MIN as i128) || b > (i32::MAX as i128) => None,
338 Self::I128(b) => Some(b as i32),
339 Self::F64(f) => FloatToInt::<i32>::to_int(f).ok(),
340 }
341 }
342
343 pub fn bitcast_u64(self) -> Option<u64> {
345 match self {
346 Self::I1(b) => Some(b as u64),
347 Self::U8(b) => Some(b as u64),
348 Self::I8(b) => Some(b as u64),
349 Self::U16(b) => Some(b as u64),
350 Self::I16(b) => Some(b as u64),
351 Self::U32(b) => Some(b as u64),
352 Self::I32(b) => Some(b as u64),
353 Self::U64(b) => Some(b),
354 Self::I64(b) => Some(b as u64),
355 Self::Felt(i) => Some(i.as_canonical_u64()),
356 Self::U128(b) if b <= (u64::MAX as u128) => Some(b as u64),
357 Self::U128(_) => None,
358 Self::I128(b) if b < (i64::MIN as i128) || b > (i64::MAX as i128) => None,
359 Self::I128(b) => Some(b as u64),
360 Self::F64(f) => FloatToInt::<u64>::to_int(f).ok(),
361 }
362 }
363
364 pub fn bitcast_i64(self) -> Option<i64> {
366 match self {
367 Self::I1(b) => Some(b as i64),
368 Self::U8(b) => Some(b as i64),
369 Self::I8(b) => Some(b as i64),
370 Self::U16(b) => Some(b as i64),
371 Self::I16(b) => Some(b as i64),
372 Self::U32(b) => Some(b as i64),
373 Self::I32(b) => Some(b as i64),
374 Self::U64(b) => Some(b as i64),
375 Self::I64(b) => Some(b),
376 Self::Felt(i) => Some(i.as_canonical_u64() as i64),
377 Self::U128(b) if b <= (u64::MAX as u128) => Some(b as i64),
378 Self::U128(_) => None,
379 Self::I128(b) if b < (i64::MIN as i128) || b > (i64::MAX as i128) => None,
380 Self::I128(b) => Some(b as i64),
381 Self::F64(f) => FloatToInt::<i64>::to_int(f).ok(),
382 }
383 }
384
385 pub fn bitcast_u128(self) -> Option<u128> {
387 match self {
388 Self::I1(b) => Some(b as u128),
389 Self::U8(b) => Some(b as u128),
390 Self::I8(b) => Some(b as u128),
391 Self::U16(b) => Some(b as u128),
392 Self::I16(b) => Some(b as u128),
393 Self::U32(b) => Some(b as u128),
394 Self::I32(b) => Some(b as u128),
395 Self::U64(b) => Some(b as u128),
396 Self::I64(b) => Some(b as u128),
397 Self::Felt(i) => Some(i.as_canonical_u64() as u128),
398 Self::U128(b) => Some(b),
399 Self::I128(b) => Some(b as u128),
400 Self::F64(f) => FloatToInt::<u128>::to_int(f).ok(),
401 }
402 }
403
404 pub fn bitcast_i128(self) -> Option<i128> {
406 match self {
407 Self::I1(b) => Some(b as i128),
408 Self::U8(b) => Some(b as i128),
409 Self::I8(b) => Some(b as i128),
410 Self::U16(b) => Some(b as i128),
411 Self::I16(b) => Some(b as i128),
412 Self::U32(b) => Some(b as i128),
413 Self::I32(b) => Some(b as i128),
414 Self::U64(b) => Some(b as i128),
415 Self::I64(b) => Some(b as i128),
416 Self::Felt(i) => Some(i.as_canonical_u64() as i128),
417 Self::U128(b) => Some(b as i128),
418 Self::I128(b) => Some(b),
419 Self::F64(f) => FloatToInt::<i128>::to_int(f).ok(),
420 }
421 }
422
423 pub fn bitcast_felt(self) -> Option<Felt> {
425 match self {
426 Self::Felt(value) => Some(value),
427 imm => imm.bitcast_u64().and_then(|value| Felt::new(value).ok()),
428 }
429 }
430
431 pub fn bitcast_f64(self) -> Option<f64> {
433 match self {
434 Self::I1(b) => Some(f64::from(b as u32)),
435 Self::U8(b) => Some(f64::from(b as u32)),
436 Self::I8(b) => Some(f64::from(b as i32)),
437 Self::U16(b) => Some(f64::from(b as u32)),
438 Self::I16(b) => Some(f64::from(b as i32)),
439 Self::U32(b) => Some(f64::from(b)),
440 Self::I32(b) => Some(f64::from(b)),
441 Self::U64(b) => Some(b as f64),
442 Self::I64(b) => Some(b as f64),
443 Self::Felt(i) => Some(i.as_canonical_u64() as f64),
444 Self::U128(b) => Some(b as f64),
445 Self::I128(b) => Some(b as f64),
446 Self::F64(f) => Some(f),
447 }
448 }
449
450 pub fn as_u8(self) -> Option<u8> {
452 match self {
453 Self::I1(b) => Some(b as u8),
454 Self::U8(b) => Some(b),
455 Self::I8(b) if b >= 0 => Some(b as u8),
456 Self::I8(_) => None,
457 Self::U16(b) => b.try_into().ok(),
458 Self::I16(b) if b >= 0 && b <= (u8::MAX as i16) => Some(b as u16 as u8),
459 Self::I16(_) => None,
460 Self::U32(b) => b.try_into().ok(),
461 Self::I32(b) if b >= 0 && b <= (u8::MAX as i32) => Some(b as u32 as u8),
462 Self::I32(_) => None,
463 Self::U64(b) => b.try_into().ok(),
464 Self::I64(b) if b >= 0 && b <= (u8::MAX as i64) => Some(b as u64 as u8),
465 Self::I64(_) => None,
466 Self::Felt(i) => i.as_canonical_u64().try_into().ok(),
467 Self::U128(b) => b.try_into().ok(),
468 Self::I128(b) if b >= 0 && b <= (u8::MAX as i128) => Some(b as u8),
469 Self::I128(_) => None,
470 Self::F64(f) => FloatToInt::<u8>::to_int(f).ok(),
471 }
472 }
473
474 pub fn as_i8(self) -> Option<i8> {
476 match self {
477 Self::I1(i) => Some(i as u8 as i8),
478 Self::U8(i) => i.try_into().ok(),
479 Self::I8(i) => Some(i),
480 Self::U16(i) if i <= (i8::MAX as u16) => Some(i as i8),
481 Self::U16(_) => None,
482 Self::I16(i) => i.try_into().ok(),
483 Self::U32(i) if i <= (i8::MAX as u32) => Some(i as i8),
484 Self::U32(_) => None,
485 Self::I32(i) => i.try_into().ok(),
486 Self::U64(i) if i <= (i8::MAX as u64) => Some(i as i8),
487 Self::U64(_) => None,
488 Self::I64(i) => i.try_into().ok(),
489 Self::Felt(i) => i.as_canonical_u64().try_into().ok(),
490 Self::U128(i) if i <= (i8::MAX as u128) => Some(i as i8),
491 Self::U128(_) => None,
492 Self::I128(i) if i >= (i8::MIN as i128) && i <= (i8::MAX as i128) => Some(i as i8),
493 Self::I128(_) => None,
494 Self::F64(f) => FloatToInt::<i8>::to_int(f).ok(),
495 }
496 }
497
498 pub fn as_u16(self) -> Option<u16> {
500 match self {
501 Self::I1(b) => Some(b as u16),
502 Self::U8(b) => Some(b as u16),
503 Self::I8(b) if b >= 0 => Some(b as u16),
504 Self::I8(_) => None,
505 Self::U16(b) => Some(b),
506 Self::I16(b) if b >= 0 => Some(b as u16),
507 Self::I16(_) => None,
508 Self::U32(b) => b.try_into().ok(),
509 Self::I32(b) if b >= 0 && b <= (u16::MAX as i32) => Some(b as u32 as u16),
510 Self::I32(_) => None,
511 Self::U64(b) => b.try_into().ok(),
512 Self::I64(b) if b >= 0 => u64::try_from(b).ok()?.try_into().ok(),
513 Self::I64(_) => None,
514 Self::Felt(i) => i.as_canonical_u64().try_into().ok(),
515 Self::U128(b) if b <= (u16::MAX as u64 as u128) => Some(b as u16),
516 Self::U128(_) => None,
517 Self::I128(b) if b >= 0 && b <= (u16::MAX as i128) => Some(b as u16),
518 Self::I128(_) => None,
519 Self::F64(f) => FloatToInt::<u16>::to_int(f).ok(),
520 }
521 }
522
523 pub fn as_i16(self) -> Option<i16> {
525 match self {
526 Self::I1(b) => Some(b as u16 as i16),
527 Self::U8(i) => Some(i as i16),
528 Self::I8(i) => Some(i as i16),
529 Self::U16(i) if i <= (i16::MAX as u16) => Some(i as i16),
530 Self::U16(_) => None,
531 Self::I16(i) => Some(i),
532 Self::U32(i) if i <= (i16::MAX as u32) => Some(i as i16),
533 Self::U32(_) => None,
534 Self::I32(i) => i.try_into().ok(),
535 Self::U64(i) if i <= (i16::MAX as u64) => Some(i as i16),
536 Self::U64(_) => None,
537 Self::I64(i) => i.try_into().ok(),
538 Self::Felt(i) => i.as_canonical_u64().try_into().ok(),
539 Self::U128(i) if i <= (i16::MAX as u16 as u128) => Some(i as u16 as i16),
540 Self::U128(_) => None,
541 Self::I128(i) if i >= (i16::MIN as i128) && i <= (i16::MAX as i128) => Some(i as i16),
542 Self::I128(_) => None,
543 Self::F64(f) => FloatToInt::<i16>::to_int(f).ok(),
544 }
545 }
546
547 pub fn as_u32(self) -> Option<u32> {
549 match self {
550 Self::I1(b) => Some(b as u32),
551 Self::U8(b) => Some(b as u32),
552 Self::I8(b) if b >= 0 => Some(b as u32),
553 Self::I8(_) => None,
554 Self::U16(b) => Some(b as u32),
555 Self::I16(b) if b >= 0 => Some(b as u32),
556 Self::I16(_) => None,
557 Self::U32(b) => Some(b),
558 Self::I32(b) if b >= 0 => Some(b as u32),
559 Self::I32(_) => None,
560 Self::U64(b) => u32::try_from(b).ok(),
561 Self::I64(b) if b >= 0 => u32::try_from(b as u64).ok(),
562 Self::I64(_) => None,
563 Self::Felt(i) => u32::try_from(i.as_canonical_u64()).ok(),
564 Self::U128(b) if b <= (u32::MAX as u64 as u128) => Some(b as u32),
565 Self::U128(_) => None,
566 Self::I128(b) if b >= 0 && b <= (u32::MAX as u64 as i128) => Some(b as u32),
567 Self::I128(_) => None,
568 Self::F64(f) => FloatToInt::<u32>::to_int(f).ok(),
569 }
570 }
571
572 pub fn as_i32(self) -> Option<i32> {
574 match self {
575 Self::I1(b) => Some(b as u32 as i32),
576 Self::U8(i) => Some(i as i32),
577 Self::I8(i) => Some(i as i32),
578 Self::U16(i) => Some(i as i32),
579 Self::I16(i) => Some(i as i32),
580 Self::U32(i) => i.try_into().ok(),
581 Self::I32(i) => Some(i),
582 Self::U64(i) => i.try_into().ok(),
583 Self::I64(i) => i.try_into().ok(),
584 Self::Felt(i) => i.as_canonical_u64().try_into().ok(),
585 Self::U128(i) if i <= (i32::MAX as u32 as u128) => Some(i as u32 as i32),
586 Self::U128(_) => None,
587 Self::I128(i) if i >= (i32::MIN as i128) && i <= (i32::MAX as i128) => Some(i as i32),
588 Self::I128(_) => None,
589 Self::F64(f) => FloatToInt::<i32>::to_int(f).ok(),
590 }
591 }
592
593 pub fn as_felt(self) -> Option<Felt> {
595 match self {
596 Self::I1(b) => Felt::new(b as u64).ok(),
597 Self::U8(b) => Felt::new(b as u64).ok(),
598 Self::I8(b) => u64::try_from(b).ok().and_then(|value| Felt::new(value).ok()),
599 Self::U16(b) => Felt::new(b as u64).ok(),
600 Self::I16(b) => u64::try_from(b).ok().and_then(|value| Felt::new(value).ok()),
601 Self::U32(b) => Felt::new(b as u64).ok(),
602 Self::I32(b) => u64::try_from(b).ok().and_then(|value| Felt::new(value).ok()),
603 Self::U64(b) => Felt::new(b).ok(),
604 Self::I64(b) => u64::try_from(b).ok().and_then(|value| Felt::new(value).ok()),
605 Self::Felt(i) => Some(i),
606 Self::U128(b) => u64::try_from(b).ok().and_then(|value| Felt::new(value).ok()),
607 Self::I128(b) => u64::try_from(b).ok().and_then(|value| Felt::new(value).ok()),
608 Self::F64(f) => FloatToInt::<Felt>::to_int(f).ok(),
609 }
610 }
611
612 pub fn as_u64(self) -> Option<u64> {
614 match self {
615 Self::I1(b) => Some(b as u64),
616 Self::U8(i) => Some(i as u64),
617 Self::I8(i) if i >= 0 => Some(i as u64),
618 Self::I8(_) => None,
619 Self::U16(i) => Some(i as u64),
620 Self::I16(i) if i >= 0 => Some(i as u16 as u64),
621 Self::I16(_) => None,
622 Self::U32(i) => Some(i as u64),
623 Self::I32(i) if i >= 0 => Some(i as u32 as u64),
624 Self::I32(_) => None,
625 Self::U64(i) => Some(i),
626 Self::I64(i) if i >= 0 => Some(i as u64),
627 Self::I64(_) => None,
628 Self::Felt(i) => Some(i.as_canonical_u64()),
629 Self::U128(i) => (i).try_into().ok(),
630 Self::I128(i) if i >= 0 => (i).try_into().ok(),
631 Self::I128(_) => None,
632 Self::F64(f) => FloatToInt::<u64>::to_int(f).ok(),
633 }
634 }
635
636 pub fn as_i64(self) -> Option<i64> {
638 match self {
639 Self::I1(b) => Some(b as i64),
640 Self::U8(i) => Some(i as i64),
641 Self::I8(i) => Some(i as i64),
642 Self::U16(i) => Some(i as i64),
643 Self::I16(i) => Some(i as i64),
644 Self::U32(i) => Some(i as i64),
645 Self::I32(i) => Some(i as i64),
646 Self::U64(i) => (i).try_into().ok(),
647 Self::I64(i) => Some(i),
648 Self::Felt(i) => i.as_canonical_u64().try_into().ok(),
649 Self::U128(i) if i <= i64::MAX as u128 => Some(i as u64 as i64),
650 Self::U128(_) => None,
651 Self::I128(i) => (i).try_into().ok(),
652 Self::F64(f) => FloatToInt::<i64>::to_int(f).ok(),
653 }
654 }
655
656 pub fn as_u128(self) -> Option<u128> {
658 match self {
659 Self::I1(b) => Some(b as u128),
660 Self::U8(i) => Some(i as u128),
661 Self::I8(i) if i >= 0 => Some(i as u128),
662 Self::I8(_) => None,
663 Self::U16(i) => Some(i as u128),
664 Self::I16(i) if i >= 0 => Some(i as u16 as u128),
665 Self::I16(_) => None,
666 Self::U32(i) => Some(i as u128),
667 Self::I32(i) if i >= 0 => Some(i as u32 as u128),
668 Self::I32(_) => None,
669 Self::U64(i) => Some(i as u128),
670 Self::I64(i) if i >= 0 => Some(i as u128),
671 Self::I64(_) => None,
672 Self::Felt(i) => Some(i.as_canonical_u64() as u128),
673 Self::U128(i) => Some(i),
674 Self::I128(i) if i >= 0 => (i).try_into().ok(),
675 Self::I128(_) => None,
676 Self::F64(f) => FloatToInt::<u128>::to_int(f).ok(),
677 }
678 }
679
680 pub fn as_i128(self) -> Option<i128> {
682 match self {
683 Self::I1(b) => Some(b as i128),
684 Self::U8(i) => Some(i as i128),
685 Self::I8(i) => Some(i as i128),
686 Self::U16(i) => Some(i as i128),
687 Self::I16(i) => Some(i as i128),
688 Self::U32(i) => Some(i as i128),
689 Self::I32(i) => Some(i as i128),
690 Self::U64(i) => Some(i as i128),
691 Self::I64(i) => Some(i as i128),
692 Self::Felt(i) => Some(i.as_canonical_u64() as i128),
693 Self::U128(i) if i <= i128::MAX as u128 => Some(i as i128),
694 Self::U128(_) => None,
695 Self::I128(i) => Some(i),
696 Self::F64(f) => FloatToInt::<i128>::to_int(f).ok(),
697 }
698 }
699}
700impl fmt::Display for Immediate {
701 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
702 match self {
703 Self::I1(i) => write!(f, "{i}"),
704 Self::U8(i) => write!(f, "{i}"),
705 Self::I8(i) => write!(f, "{i}"),
706 Self::U16(i) => write!(f, "{i}"),
707 Self::I16(i) => write!(f, "{i}"),
708 Self::U32(i) => write!(f, "{i}"),
709 Self::I32(i) => write!(f, "{i}"),
710 Self::U64(i) => write!(f, "{i}"),
711 Self::I64(i) => write!(f, "{i}"),
712 Self::U128(i) => write!(f, "{i}"),
713 Self::I128(i) => write!(f, "{i}"),
714 Self::F64(n) => write!(f, "{n}"),
715 Self::Felt(i) => write!(f, "{i}"),
716 }
717 }
718}
719impl PrettyPrint for Immediate {
720 fn render(&self) -> crate::formatter::Document {
721 use crate::formatter::*;
722 display(self)
723 }
724}
725impl Hash for Immediate {
726 fn hash<H: Hasher>(&self, state: &mut H) {
727 let d = core::mem::discriminant(self);
728 d.hash(state);
729 match self {
730 Self::I1(i) => i.hash(state),
731 Self::U8(i) => i.hash(state),
732 Self::I8(i) => i.hash(state),
733 Self::U16(i) => i.hash(state),
734 Self::I16(i) => i.hash(state),
735 Self::U32(i) => i.hash(state),
736 Self::I32(i) => i.hash(state),
737 Self::U64(i) => i.hash(state),
738 Self::I64(i) => i.hash(state),
739 Self::U128(i) => i.hash(state),
740 Self::I128(i) => i.hash(state),
741 Self::F64(f) => {
742 let bytes = f.to_be_bytes();
743 bytes.hash(state)
744 }
745 Self::Felt(i) => i.as_canonical_u64().hash(state),
746 }
747 }
748}
749impl Eq for Immediate {}
750impl PartialEq for Immediate {
751 fn eq(&self, other: &Self) -> bool {
752 match (*self, *other) {
753 (Self::I1(x), Self::I1(y)) => x == y,
754 (Self::I8(x), Self::I8(y)) => x == y,
755 (Self::U8(x), Self::U8(y)) => x == y,
756 (Self::U16(x), Self::U16(y)) => x == y,
757 (Self::I16(x), Self::I16(y)) => x == y,
758 (Self::U32(x), Self::U32(y)) => x == y,
759 (Self::I32(x), Self::I32(y)) => x == y,
760 (Self::U64(x), Self::U64(y)) => x == y,
761 (Self::I64(x), Self::I64(y)) => x == y,
762 (Self::U128(x), Self::U128(y)) => x == y,
763 (Self::I128(x), Self::I128(y)) => x == y,
764 (Self::F64(x), Self::F64(y)) => x == y,
765 (Self::Felt(x), Self::Felt(y)) => x == y,
766 _ => false,
767 }
768 }
769}
770impl PartialEq<isize> for Immediate {
771 fn eq(&self, other: &isize) -> bool {
772 let y = *other;
773 match *self {
774 Self::I1(x) => x == (y == 1),
775 Self::U8(_) if y < 0 => false,
776 Self::U8(x) => x as isize == y,
777 Self::I8(x) => x as isize == y,
778 Self::U16(_) if y < 0 => false,
779 Self::U16(x) => x as isize == y,
780 Self::I16(x) => x as isize == y,
781 Self::U32(_) if y < 0 => false,
782 Self::U32(x) => x as isize == y,
783 Self::I32(x) => x as isize == y,
784 Self::U64(_) if y < 0 => false,
785 Self::U64(x) => x == y as i64 as u64,
786 Self::I64(x) => x == y as i64,
787 Self::U128(_) if y < 0 => false,
788 Self::U128(x) => x == y as i128 as u128,
789 Self::I128(x) => x == y as i128,
790 Self::F64(_) => false,
791 Self::Felt(_) if y < 0 => false,
792 Self::Felt(x) => x.as_canonical_u64() == y as i64 as u64,
793 }
794 }
795}
796impl PartialOrd for Immediate {
797 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
798 Some(self.cmp(other))
799 }
800}
801impl Ord for Immediate {
802 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
803 use core::cmp::Ordering;
804
805 match (self, other) {
806 (Self::F64(x), Self::F64(y)) => x.total_cmp(y),
808 (Self::F64(x), y) => {
816 let y = y
817 .as_i128()
818 .expect("expected rhs to be an integer capable of fitting in an i128");
819 if let Ok(x) = FloatToInt::<i128>::to_int(*x) {
820 x.cmp(&y)
821 } else {
822 let is_positive = x.is_sign_positive();
823 if let Ok(x) = FloatToInt::<i128>::to_int((*x).trunc()) {
824 match x.cmp(&y) {
826 Ordering::Equal if is_positive => Ordering::Greater,
827 Ordering::Equal => Ordering::Less,
828 o => o,
829 }
830 } else {
831 if is_positive {
834 Ordering::Greater
835 } else {
836 Ordering::Less
837 }
838 }
839 }
840 }
841 (x, y @ Self::F64(_)) => y.cmp(x).reverse(),
842 (Self::U128(x), Self::U128(y)) => x.cmp(y),
844 (Self::U128(x), y) => {
845 let y = y.as_u128().expect("expected rhs to be an integer in the range of u128");
846 x.cmp(&y)
847 }
848 (x, Self::U128(y)) => {
849 let x = x.as_u128().expect("expected lhs to be an integer in the range of u128");
850 x.cmp(y)
851 }
852 (Self::I128(x), Self::I128(y)) => x.cmp(y),
854 (Self::I128(x), y) => {
856 let y = y.as_i128().expect("expected rhs to be an integer smaller than i128");
857 x.cmp(&y)
858 }
859 (x, Self::I128(y)) => {
860 let x = x.as_i128().expect("expected lhs to be an integer smaller than i128");
861 x.cmp(y)
862 }
863 (Self::U64(x), Self::U64(y)) => x.cmp(y),
865 (Self::U64(x), y) => {
867 let y =
868 y.as_i64().expect("expected rhs to be an integer capable of fitting in an i64")
869 as u64;
870 x.cmp(&y)
871 }
872 (x, Self::U64(y)) => {
873 let x =
874 x.as_i64().expect("expected lhs to be an integer capable of fitting in an i64")
875 as u64;
876 x.cmp(y)
877 }
878 (x, y) => {
880 let x =
881 x.as_i64().expect("expected lhs to be an integer capable of fitting in an i64");
882 let y =
883 y.as_i64().expect("expected rhs to be an integer capable of fitting in an i64");
884 x.cmp(&y)
885 }
886 }
887 }
888}
889impl From<Immediate> for Type {
890 #[inline]
891 fn from(imm: Immediate) -> Self {
892 imm.ty()
893 }
894}
895impl From<&Immediate> for Type {
896 #[inline(always)]
897 fn from(imm: &Immediate) -> Self {
898 imm.ty()
899 }
900}
901impl From<bool> for Immediate {
902 #[inline(always)]
903 fn from(value: bool) -> Self {
904 Self::I1(value)
905 }
906}
907impl From<i8> for Immediate {
908 #[inline(always)]
909 fn from(value: i8) -> Self {
910 Self::I8(value)
911 }
912}
913impl From<u8> for Immediate {
914 #[inline(always)]
915 fn from(value: u8) -> Self {
916 Self::U8(value)
917 }
918}
919impl From<i16> for Immediate {
920 #[inline(always)]
921 fn from(value: i16) -> Self {
922 Self::I16(value)
923 }
924}
925impl From<u16> for Immediate {
926 #[inline(always)]
927 fn from(value: u16) -> Self {
928 Self::U16(value)
929 }
930}
931impl From<i32> for Immediate {
932 #[inline(always)]
933 fn from(value: i32) -> Self {
934 Self::I32(value)
935 }
936}
937impl From<u32> for Immediate {
938 #[inline(always)]
939 fn from(value: u32) -> Self {
940 Self::U32(value)
941 }
942}
943impl From<i64> for Immediate {
944 #[inline(always)]
945 fn from(value: i64) -> Self {
946 Self::I64(value)
947 }
948}
949impl From<u64> for Immediate {
950 #[inline(always)]
951 fn from(value: u64) -> Self {
952 Self::U64(value)
953 }
954}
955impl From<u128> for Immediate {
956 #[inline(always)]
957 fn from(value: u128) -> Self {
958 Self::U128(value)
959 }
960}
961impl From<i128> for Immediate {
962 #[inline(always)]
963 fn from(value: i128) -> Self {
964 Self::I128(value)
965 }
966}
967impl From<usize> for Immediate {
968 #[inline(always)]
969 fn from(value: usize) -> Self {
970 Self::U64(value as u64)
971 }
972}
973impl From<isize> for Immediate {
974 #[inline(always)]
975 fn from(value: isize) -> Self {
976 Self::I64(value as i64)
977 }
978}
979impl From<f64> for Immediate {
980 #[inline(always)]
981 fn from(value: f64) -> Self {
982 Self::F64(value)
983 }
984}
985impl From<char> for Immediate {
986 #[inline(always)]
987 fn from(value: char) -> Self {
988 Self::I32(value as u32 as i32)
989 }
990}
991impl From<Felt> for Immediate {
992 #[inline(always)]
993 fn from(value: Felt) -> Self {
994 Self::Felt(value)
995 }
996}
997
998trait FloatToInt<T: Sized + Copy>: Sized {
999 const ZERO: T;
1000
1001 fn upper_bound() -> Self;
1002 fn lower_bound() -> Self;
1003 fn to_int(self) -> Result<T, ()>;
1004 unsafe fn to_int_unchecked(self) -> T;
1005}
1006impl FloatToInt<i8> for f64 {
1007 const ZERO: i8 = 0;
1008
1009 fn upper_bound() -> Self {
1010 f64::from(i8::MAX) + 1.0
1011 }
1012
1013 fn lower_bound() -> Self {
1014 f64::from(i8::MIN) - 1.0
1015 }
1016
1017 fn to_int(self) -> Result<i8, ()> {
1018 float_to_int(self)
1019 }
1020
1021 unsafe fn to_int_unchecked(self) -> i8 {
1022 unsafe { f64::to_int_unchecked(self) }
1023 }
1024}
1025impl FloatToInt<u8> for f64 {
1026 const ZERO: u8 = 0;
1027
1028 fn upper_bound() -> Self {
1029 f64::from(u8::MAX) + 1.0
1030 }
1031
1032 fn lower_bound() -> Self {
1033 0.0
1034 }
1035
1036 fn to_int(self) -> Result<u8, ()> {
1037 float_to_int(self)
1038 }
1039
1040 unsafe fn to_int_unchecked(self) -> u8 {
1041 unsafe { f64::to_int_unchecked(self) }
1042 }
1043}
1044impl FloatToInt<i16> for f64 {
1045 const ZERO: i16 = 0;
1046
1047 fn upper_bound() -> Self {
1048 f64::from(i16::MAX) + 1.0
1049 }
1050
1051 fn lower_bound() -> Self {
1052 f64::from(i16::MIN) - 1.0
1053 }
1054
1055 fn to_int(self) -> Result<i16, ()> {
1056 float_to_int(self)
1057 }
1058
1059 unsafe fn to_int_unchecked(self) -> i16 {
1060 unsafe { f64::to_int_unchecked(self) }
1061 }
1062}
1063impl FloatToInt<u16> for f64 {
1064 const ZERO: u16 = 0;
1065
1066 fn upper_bound() -> Self {
1067 f64::from(u16::MAX) + 1.0
1068 }
1069
1070 fn lower_bound() -> Self {
1071 0.0
1072 }
1073
1074 fn to_int(self) -> Result<u16, ()> {
1075 float_to_int(self)
1076 }
1077
1078 unsafe fn to_int_unchecked(self) -> u16 {
1079 unsafe { f64::to_int_unchecked(self) }
1080 }
1081}
1082impl FloatToInt<i32> for f64 {
1083 const ZERO: i32 = 0;
1084
1085 fn upper_bound() -> Self {
1086 f64::from(i32::MAX) + 1.0
1087 }
1088
1089 fn lower_bound() -> Self {
1090 f64::from(i32::MIN) - 1.0
1091 }
1092
1093 fn to_int(self) -> Result<i32, ()> {
1094 float_to_int(self)
1095 }
1096
1097 unsafe fn to_int_unchecked(self) -> i32 {
1098 unsafe { f64::to_int_unchecked(self) }
1099 }
1100}
1101impl FloatToInt<u32> for f64 {
1102 const ZERO: u32 = 0;
1103
1104 fn upper_bound() -> Self {
1105 f64::from(u32::MAX) + 1.0
1106 }
1107
1108 fn lower_bound() -> Self {
1109 0.0
1110 }
1111
1112 fn to_int(self) -> Result<u32, ()> {
1113 float_to_int(self)
1114 }
1115
1116 unsafe fn to_int_unchecked(self) -> u32 {
1117 unsafe { f64::to_int_unchecked(self) }
1118 }
1119}
1120impl FloatToInt<i64> for f64 {
1121 const ZERO: i64 = 0;
1122
1123 fn upper_bound() -> Self {
1124 63.0f64.exp2()
1125 }
1126
1127 fn lower_bound() -> Self {
1128 -63.0f64.exp2() - 1.0
1129 }
1130
1131 fn to_int(self) -> Result<i64, ()> {
1132 float_to_int(self)
1133 }
1134
1135 unsafe fn to_int_unchecked(self) -> i64 {
1136 unsafe { f64::to_int_unchecked(self) }
1137 }
1138}
1139impl FloatToInt<u64> for f64 {
1140 const ZERO: u64 = 0;
1141
1142 fn upper_bound() -> Self {
1143 64.0f64.exp2()
1144 }
1145
1146 fn lower_bound() -> Self {
1147 0.0
1148 }
1149
1150 fn to_int(self) -> Result<u64, ()> {
1151 float_to_int(self)
1152 }
1153
1154 unsafe fn to_int_unchecked(self) -> u64 {
1155 unsafe { f64::to_int_unchecked(self) }
1156 }
1157}
1158impl FloatToInt<Felt> for f64 {
1159 const ZERO: Felt = Felt::ZERO;
1160
1161 fn upper_bound() -> Self {
1162 64.0f64.exp2() - 32.0f64.exp2() + 1.0
1163 }
1164
1165 fn lower_bound() -> Self {
1166 0.0
1167 }
1168
1169 fn to_int(self) -> Result<Felt, ()> {
1170 float_to_int(self).and_then(|value| Felt::new(value).map_err(|_| ()))
1171 }
1172
1173 unsafe fn to_int_unchecked(self) -> Felt {
1174 Felt::new_unchecked(unsafe { f64::to_int_unchecked::<u64>(self) })
1175 }
1176}
1177impl FloatToInt<u128> for f64 {
1178 const ZERO: u128 = 0;
1179
1180 fn upper_bound() -> Self {
1181 128.0f64.exp2()
1182 }
1183
1184 fn lower_bound() -> Self {
1185 0.0
1186 }
1187
1188 fn to_int(self) -> Result<u128, ()> {
1189 float_to_int(self)
1190 }
1191
1192 unsafe fn to_int_unchecked(self) -> u128 {
1193 unsafe { f64::to_int_unchecked(self) }
1194 }
1195}
1196impl FloatToInt<i128> for f64 {
1197 const ZERO: i128 = 0;
1198
1199 fn upper_bound() -> Self {
1200 f64::from(i128::BITS - 1).exp2()
1201 }
1202
1203 fn lower_bound() -> Self {
1204 (-f64::from(i128::BITS - 1)).exp2() - 1.0
1205 }
1206
1207 fn to_int(self) -> Result<i128, ()> {
1208 float_to_int(self)
1209 }
1210
1211 unsafe fn to_int_unchecked(self) -> i128 {
1212 unsafe { f64::to_int_unchecked(self) }
1213 }
1214}
1215
1216fn float_to_int<I>(f: f64) -> Result<I, ()>
1217where
1218 I: Copy,
1219 f64: FloatToInt<I>,
1220{
1221 use core::num::FpCategory;
1222 match f.classify() {
1223 FpCategory::Nan | FpCategory::Infinite | FpCategory::Subnormal => Err(()),
1224 FpCategory::Zero => Ok(<f64 as FloatToInt<I>>::ZERO),
1225 FpCategory::Normal => {
1226 if f == f.trunc()
1227 && f > <f64 as FloatToInt<I>>::lower_bound()
1228 && f < <f64 as FloatToInt<I>>::upper_bound()
1229 {
1230 Ok(unsafe { <f64 as FloatToInt<I>>::to_int_unchecked(f) })
1232 } else {
1233 Err(())
1234 }
1235 }
1236 }
1237}