cairo_lang_sierra/extensions/modules/
snapshot.rs

1use crate::extensions::lib_func::{
2    LibfuncSignature, OutputVarInfo, ParamSignature, SierraApChange, SignatureOnlyGenericLibfunc,
3    SignatureSpecializationContext,
4};
5use crate::extensions::type_specialization_context::TypeSpecializationContext;
6use crate::extensions::types::{
7    GenericTypeArgGenericType, GenericTypeArgGenericTypeWrapper, TypeInfo,
8};
9use crate::extensions::{
10    NamedType, OutputVarReferenceInfo, SpecializationError, args_as_single_type,
11};
12use crate::ids::{ConcreteTypeId, GenericTypeId};
13use crate::program::GenericArg;
14
15/// Type for a type's snapshot.
16#[derive(Default)]
17pub struct SnapshotTypeWrapped {}
18impl GenericTypeArgGenericType for SnapshotTypeWrapped {
19    const ID: GenericTypeId = GenericTypeId::new_inline("Snapshot");
20
21    fn calc_info(
22        &self,
23        _context: &dyn TypeSpecializationContext,
24        long_id: crate::program::ConcreteTypeLongId,
25        TypeInfo { zero_sized, storable, duplicatable, .. }: TypeInfo,
26    ) -> Result<TypeInfo, SpecializationError> {
27        // Duplicatable types are their own snapshot - as the snapshot itself is useless if we can
28        // dup the value already.
29        if storable && !duplicatable {
30            Ok(TypeInfo {
31                long_id,
32                zero_sized,
33                storable: true,
34                droppable: true,
35                duplicatable: true,
36            })
37        } else {
38            Err(SpecializationError::UnsupportedGenericArg)
39        }
40    }
41}
42pub type SnapshotType = GenericTypeArgGenericTypeWrapper<SnapshotTypeWrapped>;
43
44/// Returns the type snapshot for a given type `T`.
45/// For duplicatable returns `T` itself, as a regular dup is already a snapshot.
46pub fn snapshot_ty(
47    context: &dyn SignatureSpecializationContext,
48    ty: ConcreteTypeId,
49) -> Result<ConcreteTypeId, SpecializationError> {
50    if context.get_type_info(ty.clone())?.duplicatable {
51        Ok(ty)
52    } else {
53        context.get_wrapped_concrete_type(SnapshotType::id(), ty)
54    }
55}
56
57/// Libfunc for taking a snapshot `Snapshot<T>` from a T.
58#[derive(Default)]
59pub struct SnapshotTakeLibfunc {}
60impl SignatureOnlyGenericLibfunc for SnapshotTakeLibfunc {
61    const STR_ID: &'static str = "snapshot_take";
62
63    fn specialize_signature(
64        &self,
65        context: &dyn SignatureSpecializationContext,
66        args: &[GenericArg],
67    ) -> Result<LibfuncSignature, SpecializationError> {
68        let ty = args_as_single_type(args)?;
69        Ok(LibfuncSignature::new_non_branch_ex(
70            vec![ParamSignature {
71                ty: ty.clone(),
72                allow_deferred: true,
73                allow_add_const: true,
74                allow_const: true,
75            }],
76            vec![
77                OutputVarInfo {
78                    ty: ty.clone(),
79                    ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
80                },
81                OutputVarInfo {
82                    ty: snapshot_ty(context, ty)?,
83                    ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
84                },
85            ],
86            SierraApChange::Known { new_vars_only: true },
87        ))
88    }
89}