cairo_lang_sierra/extensions/modules/
snapshot.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use crate::extensions::lib_func::{
    LibfuncSignature, OutputVarInfo, ParamSignature, SierraApChange, SignatureOnlyGenericLibfunc,
    SignatureSpecializationContext,
};
use crate::extensions::type_specialization_context::TypeSpecializationContext;
use crate::extensions::types::{
    GenericTypeArgGenericType, GenericTypeArgGenericTypeWrapper, TypeInfo,
};
use crate::extensions::{
    args_as_single_type, NamedType, OutputVarReferenceInfo, SpecializationError,
};
use crate::ids::{ConcreteTypeId, GenericTypeId};
use crate::program::GenericArg;

/// Type for a type's snapshot.
#[derive(Default)]
pub struct SnapshotTypeWrapped {}
impl GenericTypeArgGenericType for SnapshotTypeWrapped {
    const ID: GenericTypeId = GenericTypeId::new_inline("Snapshot");

    fn calc_info(
        &self,
        _context: &dyn TypeSpecializationContext,
        long_id: crate::program::ConcreteTypeLongId,
        TypeInfo { zero_sized, storable, duplicatable, .. }: TypeInfo,
    ) -> Result<TypeInfo, SpecializationError> {
        // Duplicatable types are their own snapshot - as the snapshot itself is useless if we can
        // dup the value already.
        if storable && !duplicatable {
            Ok(TypeInfo {
                long_id,
                zero_sized,
                storable: true,
                droppable: true,
                duplicatable: true,
            })
        } else {
            Err(SpecializationError::UnsupportedGenericArg)
        }
    }
}
pub type SnapshotType = GenericTypeArgGenericTypeWrapper<SnapshotTypeWrapped>;

/// Returns the type snapshot for a given type `T`.
/// For duplicatable returns `T` itself, as a regular dup is already a snapshot.
pub fn snapshot_ty(
    context: &dyn SignatureSpecializationContext,
    ty: ConcreteTypeId,
) -> Result<ConcreteTypeId, SpecializationError> {
    if context.get_type_info(ty.clone())?.duplicatable {
        Ok(ty)
    } else {
        context.get_wrapped_concrete_type(SnapshotType::id(), ty)
    }
}

/// Libfunc for taking a snapshot `Snapshot<T>` from a T.
#[derive(Default)]
pub struct SnapshotTakeLibfunc {}
impl SignatureOnlyGenericLibfunc for SnapshotTakeLibfunc {
    const STR_ID: &'static str = "snapshot_take";

    fn specialize_signature(
        &self,
        context: &dyn SignatureSpecializationContext,
        args: &[GenericArg],
    ) -> Result<LibfuncSignature, SpecializationError> {
        let ty = args_as_single_type(args)?;
        Ok(LibfuncSignature::new_non_branch_ex(
            vec![ParamSignature {
                ty: ty.clone(),
                allow_deferred: true,
                allow_add_const: true,
                allow_const: true,
            }],
            vec![
                OutputVarInfo {
                    ty: ty.clone(),
                    ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
                },
                OutputVarInfo {
                    ty: snapshot_ty(context, ty)?,
                    ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
                },
            ],
            SierraApChange::Known { new_vars_only: true },
        ))
    }
}