cairo_lang_sierra/extensions/modules/
structure.rs1use cairo_lang_utils::try_extract_matches;
15
16use super::snapshot::snapshot_ty;
17use crate::define_libfunc_hierarchy;
18use crate::extensions::lib_func::{
19 DeferredOutputKind, LibfuncSignature, OutputVarInfo, ParamSignature, SierraApChange,
20 SignatureOnlyGenericLibfunc, SignatureSpecializationContext,
21};
22use crate::extensions::type_specialization_context::TypeSpecializationContext;
23use crate::extensions::types::TypeInfo;
24use crate::extensions::{
25 ConcreteType, NamedType, OutputVarReferenceInfo, SpecializationError, args_as_single_type,
26};
27use crate::ids::{ConcreteTypeId, GenericTypeId};
28use crate::program::{ConcreteTypeLongId, GenericArg};
29
30#[derive(Default)]
32pub struct StructType {}
33impl NamedType for StructType {
34 type Concrete = StructConcreteType;
35 const ID: GenericTypeId = GenericTypeId::new_inline("Struct");
36
37 fn specialize(
38 &self,
39 context: &dyn TypeSpecializationContext,
40 args: &[GenericArg],
41 ) -> Result<Self::Concrete, SpecializationError> {
42 Self::Concrete::new(context, args)
43 }
44}
45
46pub struct StructConcreteType {
47 pub info: TypeInfo,
48 pub members: Vec<ConcreteTypeId>,
49}
50impl StructConcreteType {
51 fn new(
52 context: &dyn TypeSpecializationContext,
53 args: &[GenericArg],
54 ) -> Result<Self, SpecializationError> {
55 let mut args_iter = args.iter();
56 args_iter
57 .next()
58 .and_then(|arg| try_extract_matches!(arg, GenericArg::UserType))
59 .ok_or(SpecializationError::UnsupportedGenericArg)?;
60 let mut duplicatable = true;
61 let mut droppable = true;
62 let mut storable = true;
63 let mut members: Vec<ConcreteTypeId> = Vec::new();
64 let mut zero_sized = true;
65 for arg in args_iter {
66 let ty = try_extract_matches!(arg, GenericArg::Type)
67 .ok_or(SpecializationError::UnsupportedGenericArg)?
68 .clone();
69 let info = context.get_type_info(ty.clone())?;
70 if !info.storable {
71 storable = false;
72 }
73 if !info.duplicatable {
74 duplicatable = false;
75 }
76 if !info.droppable {
77 droppable = false;
78 }
79 zero_sized = zero_sized && info.zero_sized;
80 members.push(ty);
81 }
82 Ok(StructConcreteType {
83 info: TypeInfo {
84 long_id: ConcreteTypeLongId {
85 generic_id: "Struct".into(),
86 generic_args: args.to_vec(),
87 },
88 duplicatable,
89 droppable,
90 storable,
91 zero_sized,
92 },
93 members,
94 })
95 }
96
97 fn try_from_long_id(
100 context: &dyn SignatureSpecializationContext,
101 long_id: &ConcreteTypeLongId,
102 ) -> Result<Self, SpecializationError> {
103 if long_id.generic_id != StructType::ID {
104 return Err(SpecializationError::UnsupportedGenericArg);
105 }
106 Self::new(context.as_type_specialization_context(), &long_id.generic_args)
107 }
108
109 pub fn try_from_concrete_type(
111 context: &dyn SignatureSpecializationContext,
112 ty: &ConcreteTypeId,
113 ) -> Result<Self, SpecializationError> {
114 let long_id = context.get_type_info(ty.clone())?.long_id;
115 Self::try_from_long_id(context, &long_id)
116 }
117}
118impl ConcreteType for StructConcreteType {
119 fn info(&self) -> &TypeInfo {
120 &self.info
121 }
122}
123
124define_libfunc_hierarchy! {
125 pub enum StructLibfunc {
126 Construct(StructConstructLibfunc),
127 Deconstruct(StructDeconstructLibfunc),
128 SnapshotDeconstruct(StructSnapshotDeconstructLibfunc),
129 }, StructConcreteLibfunc
130}
131
132#[derive(Default)]
134pub struct StructConstructLibfunc {}
135impl SignatureOnlyGenericLibfunc for StructConstructLibfunc {
136 const STR_ID: &'static str = "struct_construct";
137
138 fn specialize_signature(
139 &self,
140 context: &dyn SignatureSpecializationContext,
141 args: &[GenericArg],
142 ) -> Result<LibfuncSignature, SpecializationError> {
143 let struct_type = args_as_single_type(args)?;
144 let type_info = context.get_type_info(struct_type.clone())?;
145 let member_types =
146 StructConcreteType::try_from_long_id(context, &type_info.long_id)?.members;
147
148 let mut opt_same_as_param_idx = None;
149 for (idx, ty) in member_types.iter().cloned().enumerate() {
150 if !context.get_type_info(ty)?.zero_sized {
151 if opt_same_as_param_idx.is_some() {
152 opt_same_as_param_idx = None;
154 break;
155 }
156 opt_same_as_param_idx = Some(idx);
157 }
158 }
159
160 Ok(LibfuncSignature::new_non_branch_ex(
161 member_types
162 .into_iter()
163 .map(|ty| ParamSignature {
164 ty,
165 allow_deferred: true,
166 allow_add_const: true,
167 allow_const: true,
168 })
169 .collect(),
170 vec![OutputVarInfo {
171 ty: struct_type,
172 ref_info: if type_info.zero_sized {
173 OutputVarReferenceInfo::ZeroSized
174 } else if let Some(param_idx) = opt_same_as_param_idx {
175 OutputVarReferenceInfo::SameAsParam { param_idx }
176 } else {
177 OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic)
178 },
179 }],
180 SierraApChange::Known { new_vars_only: true },
181 ))
182 }
183}
184
185#[derive(Default)]
187pub struct StructDeconstructLibfunc {}
188impl SignatureOnlyGenericLibfunc for StructDeconstructLibfunc {
189 const STR_ID: &'static str = "struct_deconstruct";
190
191 fn specialize_signature(
192 &self,
193 context: &dyn SignatureSpecializationContext,
194 args: &[GenericArg],
195 ) -> Result<LibfuncSignature, SpecializationError> {
196 let struct_type = args_as_single_type(args)?;
197 let member_types =
198 StructConcreteType::try_from_concrete_type(context, &struct_type)?.members;
199 Ok(LibfuncSignature::new_non_branch_ex(
200 vec![ParamSignature {
201 ty: struct_type,
202 allow_deferred: true,
203 allow_add_const: false,
204 allow_const: true,
205 }],
206 member_types
207 .into_iter()
208 .map(|ty| {
209 Ok(OutputVarInfo {
210 ty: ty.clone(),
211 ref_info: if context.get_type_info(ty)?.zero_sized {
212 OutputVarReferenceInfo::ZeroSized
213 } else {
214 OutputVarReferenceInfo::PartialParam { param_idx: 0 }
217 },
218 })
219 })
220 .collect::<Result<Vec<_>, _>>()?,
221 SierraApChange::Known { new_vars_only: true },
222 ))
223 }
224}
225
226#[derive(Default)]
228pub struct StructSnapshotDeconstructLibfunc {}
229impl SignatureOnlyGenericLibfunc for StructSnapshotDeconstructLibfunc {
230 const STR_ID: &'static str = "struct_snapshot_deconstruct";
231
232 fn specialize_signature(
233 &self,
234 context: &dyn SignatureSpecializationContext,
235 args: &[GenericArg],
236 ) -> Result<LibfuncSignature, SpecializationError> {
237 let struct_type = args_as_single_type(args)?;
238 let member_types =
239 StructConcreteType::try_from_concrete_type(context, &struct_type)?.members;
240 Ok(LibfuncSignature::new_non_branch(
241 vec![snapshot_ty(context, struct_type)?],
242 member_types
243 .into_iter()
244 .map(|ty| {
245 Ok(OutputVarInfo {
246 ty: snapshot_ty(context, ty.clone())?,
247 ref_info: if context.get_type_info(ty)?.zero_sized {
248 OutputVarReferenceInfo::ZeroSized
249 } else {
250 OutputVarReferenceInfo::PartialParam { param_idx: 0 }
253 },
254 })
255 })
256 .collect::<Result<Vec<_>, _>>()?,
257 SierraApChange::Known { new_vars_only: true },
258 ))
259 }
260}