1use crate::dag::{InternalSharing, PostOrderIterItem};
4use crate::jet::{Jet, JetEnvironment};
5use crate::types::{self, arrow::Arrow};
6use crate::{encode, BitIter, BitWriter, Cmr, FailEntropy, FinalizeError, RedeemNode, Value, Word};
7
8use std::io;
9use std::marker::PhantomData;
10use std::sync::Arc;
11
12use super::{
13 Commit, CommitData, CommitNode, Converter, Inner, Marker, NoDisconnect, NoWitness, Node,
14 Redeem, RedeemData,
15};
16use super::{CoreConstructible, DisconnectConstructible, JetConstructible, WitnessConstructible};
17
18#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
23pub enum ConstructId {}
24
25#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
26pub struct Construct<'brand> {
27 never: std::convert::Infallible,
29 phantom: std::marker::PhantomData<&'brand ()>,
31}
32
33impl<'brand> Marker for Construct<'brand> {
34 type CachedData = ConstructData<'brand>;
35 type Witness = Option<Value>;
36 type Disconnect = Option<Arc<ConstructNode<'brand>>>;
37 type SharingId = ConstructId;
38
39 fn compute_sharing_id(_: Cmr, _: &ConstructData<'brand>) -> Option<ConstructId> {
40 None
41 }
42}
43
44pub type ConstructNode<'brand> = Node<Construct<'brand>>;
45
46impl<'brand> ConstructNode<'brand> {
47 pub fn arrow(&self) -> &Arrow<'brand> {
49 self.data.arrow()
50 }
51
52 pub fn set_arrow_to_program(&self) -> Result<(), types::Error> {
54 let ctx = self.data.inference_context();
55 let unit_ty = types::Type::unit(ctx);
56 ctx.unify(
57 &self.arrow().source,
58 &unit_ty,
59 "setting root source to unit",
60 )?;
61 ctx.unify(
62 &self.arrow().target,
63 &unit_ty,
64 "setting root target to unit",
65 )?;
66 Ok(())
67 }
68
69 pub fn finalize_types(&self) -> Result<Arc<CommitNode>, types::Error> {
76 self.set_arrow_to_program()?;
77 self.finalize_types_non_program()
78 }
79
80 pub fn finalize_types_non_program(&self) -> Result<Arc<CommitNode>, types::Error> {
84 struct FinalizeTypes;
85
86 impl<'brand> Converter<Construct<'brand>, Commit> for FinalizeTypes {
87 type Error = types::Error;
88
89 fn convert_witness(
90 &mut self,
91 _: &PostOrderIterItem<&ConstructNode>,
92 _: &Option<Value>,
93 ) -> Result<NoWitness, Self::Error> {
94 Ok(NoWitness)
95 }
96
97 fn convert_disconnect(
98 &mut self,
99 _: &PostOrderIterItem<&ConstructNode>,
100 _: Option<&Arc<CommitNode>>,
101 _: &Option<Arc<ConstructNode>>,
102 ) -> Result<NoDisconnect, Self::Error> {
103 Ok(NoDisconnect)
104 }
105
106 fn convert_data(
107 &mut self,
108 data: &PostOrderIterItem<&ConstructNode>,
109 inner: Inner<&Arc<CommitNode>, &NoDisconnect, &NoWitness>,
110 ) -> Result<Arc<CommitData>, Self::Error> {
111 let converted_data = inner.map(|node| node.cached_data());
112 CommitData::new(&data.node.data.arrow, converted_data).map(Arc::new)
113 }
114 }
115
116 self.convert::<InternalSharing, _, _>(&mut FinalizeTypes)
117 }
118
119 pub fn finalize_unpruned(&self) -> Result<Arc<RedeemNode>, FinalizeError> {
132 struct Finalizer(PhantomData<()>);
133
134 impl<'brand> Converter<Construct<'brand>, Redeem> for Finalizer {
135 type Error = FinalizeError;
136
137 fn convert_witness(
138 &mut self,
139 data: &PostOrderIterItem<&ConstructNode>,
140 wit: &Option<Value>,
141 ) -> Result<Value, Self::Error> {
142 if let Some(ref wit) = wit {
143 Ok(wit.shallow_clone())
144 } else {
145 let ty = data
161 .node
162 .arrow()
163 .target
164 .finalize()
165 .map_err(FinalizeError::Type)?;
166 Ok(Value::zero(&ty))
167 }
168 }
169
170 fn convert_disconnect(
171 &mut self,
172 _: &PostOrderIterItem<&ConstructNode>,
173 maybe_converted: Option<&Arc<RedeemNode>>,
174 _: &Option<Arc<ConstructNode>>,
175 ) -> Result<Arc<RedeemNode>, Self::Error> {
176 if let Some(child) = maybe_converted {
177 Ok(Arc::clone(child))
178 } else {
179 Err(FinalizeError::DisconnectRedeemTime)
180 }
181 }
182
183 fn convert_data(
184 &mut self,
185 data: &PostOrderIterItem<&ConstructNode>,
186 inner: Inner<&Arc<RedeemNode>, &Arc<RedeemNode>, &Value>,
187 ) -> Result<Arc<RedeemData>, Self::Error> {
188 let converted_data = inner
189 .map(|node| node.cached_data())
190 .map_disconnect(|node| node.cached_data())
191 .map_witness(Value::shallow_clone);
192 Ok(Arc::new(RedeemData::new(
193 data.node.arrow().finalize().map_err(FinalizeError::Type)?,
194 converted_data,
195 )))
196 }
197 }
198
199 self.convert::<InternalSharing, _, _>(&mut Finalizer(PhantomData))
200 }
201
202 pub fn finalize_pruned<JE: JetEnvironment>(
215 &self,
216 env: &JE,
217 ) -> Result<Arc<RedeemNode>, FinalizeError> {
218 let unpruned = self.finalize_unpruned()?;
219 unpruned.prune(env).map_err(FinalizeError::Execution)
220 }
221
222 pub fn decode<I: Iterator<Item = u8>, J: Jet>(
232 context: &types::Context<'brand>,
233 mut bits: BitIter<I>,
234 ) -> Result<Arc<Self>, crate::decode::Error> {
235 let res = crate::decode::decode_expression::<I, J>(context, &mut bits)?;
236 bits.close()?;
237 Ok(res)
238 }
239
240 #[cfg(feature = "base64")]
241 #[allow(clippy::should_implement_trait)] pub fn from_str<J: Jet>(
243 context: &types::Context<'brand>,
244 s: &str,
245 ) -> Result<Arc<Self>, crate::ParseError> {
246 use crate::base64::engine::general_purpose;
247 use crate::base64::Engine as _;
248
249 let v = general_purpose::STANDARD
250 .decode(s)
251 .map_err(crate::ParseError::Base64)?;
252 let iter = crate::BitIter::new(v.into_iter());
253 Self::decode::<_, J>(context, iter)
254 .map_err(crate::DecodeError::Decode)
255 .map_err(crate::ParseError::Decode)
256 }
257
258 #[deprecated(since = "0.5.0", note = "use Self::encode_without_witness instead")]
260 pub fn encode(&self, w: &mut BitWriter<&mut dyn io::Write>) -> io::Result<usize> {
261 let program_bits = encode::encode_program(self, w)?;
262 w.flush_all()?;
263 Ok(program_bits)
264 }
265}
266
267#[derive(Clone, Debug)]
268pub struct ConstructData<'brand> {
269 arrow: Arrow<'brand>,
270}
271
272impl<'brand> ConstructData<'brand> {
273 pub fn new(arrow: Arrow<'brand>) -> Self {
275 ConstructData { arrow }
276 }
277
278 pub fn arrow(&self) -> &Arrow<'brand> {
280 &self.arrow
281 }
282}
283
284impl<'brand> CoreConstructible<'brand> for ConstructData<'brand> {
285 fn iden(inference_context: &types::Context<'brand>) -> Self {
286 ConstructData {
287 arrow: Arrow::iden(inference_context),
288 }
289 }
290
291 fn unit(inference_context: &types::Context<'brand>) -> Self {
292 ConstructData {
293 arrow: Arrow::unit(inference_context),
294 }
295 }
296
297 fn injl(child: &Self) -> Self {
298 ConstructData {
299 arrow: Arrow::injl(&child.arrow),
300 }
301 }
302
303 fn injr(child: &Self) -> Self {
304 ConstructData {
305 arrow: Arrow::injr(&child.arrow),
306 }
307 }
308
309 fn take(child: &Self) -> Self {
310 ConstructData {
311 arrow: Arrow::take(&child.arrow),
312 }
313 }
314
315 fn drop_(child: &Self) -> Self {
316 ConstructData {
317 arrow: Arrow::drop_(&child.arrow),
318 }
319 }
320
321 fn comp(left: &Self, right: &Self) -> Result<Self, types::Error> {
322 Ok(ConstructData {
323 arrow: Arrow::comp(&left.arrow, &right.arrow)?,
324 })
325 }
326
327 fn case(left: &Self, right: &Self) -> Result<Self, types::Error> {
328 Ok(ConstructData {
329 arrow: Arrow::case(&left.arrow, &right.arrow)?,
330 })
331 }
332
333 fn assertl(left: &Self, right: Cmr) -> Result<Self, types::Error> {
334 Ok(ConstructData {
335 arrow: Arrow::assertl(&left.arrow, right)?,
336 })
337 }
338
339 fn assertr(left: Cmr, right: &Self) -> Result<Self, types::Error> {
340 Ok(ConstructData {
341 arrow: Arrow::assertr(left, &right.arrow)?,
342 })
343 }
344
345 fn pair(left: &Self, right: &Self) -> Result<Self, types::Error> {
346 Ok(ConstructData {
347 arrow: Arrow::pair(&left.arrow, &right.arrow)?,
348 })
349 }
350
351 fn fail(inference_context: &types::Context<'brand>, entropy: FailEntropy) -> Self {
352 ConstructData {
353 arrow: Arrow::fail(inference_context, entropy),
354 }
355 }
356
357 fn const_word(inference_context: &types::Context<'brand>, word: Word) -> Self {
358 ConstructData {
359 arrow: Arrow::const_word(inference_context, word),
360 }
361 }
362
363 fn inference_context(&self) -> &types::Context<'brand> {
364 self.arrow.inference_context()
365 }
366}
367
368impl<'brand> DisconnectConstructible<'brand, Option<Arc<ConstructNode<'brand>>>>
369 for ConstructData<'brand>
370{
371 fn disconnect(
372 left: &Self,
373 right: &Option<Arc<ConstructNode<'brand>>>,
374 ) -> Result<Self, types::Error> {
375 let right = right.as_ref();
376 Ok(ConstructData {
377 arrow: Arrow::disconnect(&left.arrow, &right.map(|n| n.arrow()))?,
378 })
379 }
380}
381
382impl<'brand> WitnessConstructible<'brand, Option<Value>> for ConstructData<'brand> {
383 fn witness(inference_context: &types::Context<'brand>, _witness: Option<Value>) -> Self {
384 ConstructData {
385 arrow: Arrow::witness(inference_context, NoWitness),
386 }
387 }
388}
389
390impl<'brand> JetConstructible<'brand> for ConstructData<'brand> {
391 fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self {
392 ConstructData {
393 arrow: Arrow::jet(inference_context, jet),
394 }
395 }
396}
397
398#[cfg(test)]
399mod tests {
400 use super::*;
401 use crate::types::Final;
402 use crate::Value;
403
404 #[test]
405 fn occurs_check_error() {
406 types::Context::with_context(|ctx| {
407 let iden = Arc::<ConstructNode>::iden(&ctx);
408 let node = Arc::<ConstructNode>::disconnect(&iden, &Some(Arc::clone(&iden))).unwrap();
409
410 assert!(matches!(
411 node.finalize_types_non_program(),
412 Err(types::Error::OccursCheck { .. }),
413 ));
414 });
415 }
416
417 #[test]
418 fn occurs_check_2() {
419 types::Context::with_context(|ctx| {
420 let iden = Arc::<ConstructNode>::iden(&ctx);
422 let injr = Arc::<ConstructNode>::injr(&iden);
423 let pair = Arc::<ConstructNode>::pair(&injr, &iden).unwrap();
424 let drop = Arc::<ConstructNode>::drop_(&pair);
425
426 let case1 = Arc::<ConstructNode>::case(&drop, &drop).unwrap();
427 let case2 = Arc::<ConstructNode>::case(&case1, &case1).unwrap();
428
429 let comp1 = Arc::<ConstructNode>::comp(&case2, &case2).unwrap();
430 let comp2 = Arc::<ConstructNode>::comp(&comp1, &case1).unwrap();
431
432 assert!(matches!(
433 comp2.finalize_types_non_program(),
434 Err(types::Error::OccursCheck { .. }),
435 ));
436 });
437 }
438
439 #[test]
440 fn occurs_check_3() {
441 types::Context::with_context(|ctx| {
442 let wit = Arc::<ConstructNode>::witness(&ctx, None);
444 let drop = Arc::<ConstructNode>::drop_(&wit);
445
446 let comp1 = Arc::<ConstructNode>::comp(&drop, &drop).unwrap();
447 let comp2 = Arc::<ConstructNode>::comp(&comp1, &comp1).unwrap();
448 let comp3 = Arc::<ConstructNode>::comp(&comp2, &comp2).unwrap();
449 let comp4 = Arc::<ConstructNode>::comp(&comp3, &comp3).unwrap();
450 let comp5 = Arc::<ConstructNode>::comp(&comp4, &comp4).unwrap();
451
452 let case = Arc::<ConstructNode>::case(&comp5, &comp4).unwrap();
453 let drop2 = Arc::<ConstructNode>::drop_(&case);
454 let case2 = Arc::<ConstructNode>::case(&drop2, &case).unwrap();
455 let comp6 = Arc::<ConstructNode>::comp(&case2, &case2).unwrap();
456 let case3 = Arc::<ConstructNode>::case(&comp6, &comp6).unwrap();
457
458 let comp7 = Arc::<ConstructNode>::comp(&case3, &case3).unwrap();
459 let comp8 = Arc::<ConstructNode>::comp(&comp7, &comp7).unwrap();
460
461 assert!(matches!(
462 comp8.finalize_types_non_program(),
463 Err(types::Error::OccursCheck { .. }),
464 ));
465 });
466 }
467
468 #[test]
469 fn type_check_error() {
470 types::Context::with_context(|ctx| {
471 let unit = Arc::<ConstructNode>::unit(&ctx);
472 let case = Arc::<ConstructNode>::case(&unit, &unit).unwrap();
473
474 assert!(matches!(
475 Arc::<ConstructNode>::disconnect(&case, &Some(unit)),
476 Err(types::Error::Bind { .. }),
477 ));
478 });
479 }
480
481 #[test]
482 fn scribe() {
483 types::Context::with_context(|ctx| {
487 let unit = Arc::<ConstructNode>::unit(&ctx);
488 let bit0 = Arc::<ConstructNode>::const_word(&ctx, Word::u1(0));
489 let bit1 = Arc::<ConstructNode>::const_word(&ctx, Word::u1(1));
490
491 assert_eq!(
492 unit.cmr(),
493 Arc::<ConstructNode>::scribe(&ctx, &Value::unit()).cmr()
494 );
495 assert_eq!(
496 bit0.cmr(),
497 Arc::<ConstructNode>::scribe(&ctx, &Value::u1(0)).cmr()
498 );
499 assert_eq!(
500 bit1.cmr(),
501 Arc::<ConstructNode>::scribe(&ctx, &Value::u1(1)).cmr()
502 );
503 assert_eq!(
504 Arc::<ConstructNode>::const_word(&ctx, Word::u2(1)).cmr(),
505 Arc::<ConstructNode>::scribe(&ctx, &Value::u2(1)).cmr()
506 );
507 assert_eq!(
508 Arc::<ConstructNode>::injl(&bit0).cmr(),
509 Arc::<ConstructNode>::scribe(&ctx, &Value::left(Value::u1(0), Final::unit())).cmr()
510 );
511 assert_eq!(
512 Arc::<ConstructNode>::injr(&bit1).cmr(),
513 Arc::<ConstructNode>::scribe(&ctx, &Value::right(Final::unit(), Value::u1(1)))
514 .cmr()
515 );
516 assert_eq!(
517 Arc::<ConstructNode>::pair(&unit, &unit).unwrap().cmr(),
518 Arc::<ConstructNode>::scribe(&ctx, &Value::product(Value::unit(), Value::unit()))
519 .cmr()
520 );
521 });
522 }
523
524 #[test]
525 fn regression_286_1() {
526 types::Context::with_context(|ctx| {
529 let cmr = Cmr::from_byte_array([0xde; 32]);
530
531 let u0 = Arc::<ConstructNode>::unit(&ctx);
532 let i1 = Arc::<ConstructNode>::injl(&u0);
533 let i2 = Arc::<ConstructNode>::injr(&i1);
534 let i3 = Arc::<ConstructNode>::injr(&i2);
535 let i4 = Arc::<ConstructNode>::injl(&i3);
536 let u5 = Arc::<ConstructNode>::unit(&ctx);
537 let i6 = Arc::<ConstructNode>::injl(&u5);
538 let i7 = Arc::<ConstructNode>::injr(&i6);
539 let p8 = Arc::<ConstructNode>::pair(&i4, &i7).unwrap();
540 let u9 = Arc::<ConstructNode>::unit(&ctx);
541 let a10 = Arc::<ConstructNode>::assertr(cmr, &u9).unwrap();
542 let u11 = Arc::<ConstructNode>::unit(&ctx);
543 let a12 = Arc::<ConstructNode>::assertr(cmr, &u11).unwrap();
544 let a13 = Arc::<ConstructNode>::assertl(&a12, cmr).unwrap();
545 let c14 = Arc::<ConstructNode>::case(&a10, &a13).unwrap();
546 let c15 = Arc::<ConstructNode>::comp(&p8, &c14).unwrap();
547
548 let finalized: Arc<CommitNode> = c15.finalize_types().unwrap();
549 let prog = finalized.to_vec_without_witness();
550 assert_eq!(
552 hex::DisplayHex::as_hex(&prog).to_string(),
553 "dc920a28812b6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f243090e00b10e00680",
554 );
555
556 let prog = BitIter::from(prog);
557 let decode = CommitNode::decode::<_, crate::jet::Core>(prog).unwrap();
558
559 assert_eq!(finalized, decode);
561 });
562 }
563
564 #[test]
565 fn regression_286_2() {
566 types::Context::with_context(|ctx| {
574 let w0 = Arc::<ConstructNode>::witness(&ctx, None);
575 let i1 = Arc::<ConstructNode>::iden(&ctx);
576 let d2 = Arc::<ConstructNode>::drop_(&i1);
577 let i3 = Arc::<ConstructNode>::iden(&ctx);
578 let i4 = Arc::<ConstructNode>::iden(&ctx);
579 let t5 = Arc::<ConstructNode>::take(&i4);
580 let ca6 = Arc::<ConstructNode>::case(&i3, &t5).unwrap();
581 let ca7 = Arc::<ConstructNode>::case(&d2, &ca6).unwrap();
582 let c8 = Arc::<ConstructNode>::comp(&w0, &ca7).unwrap();
583 let u9 = Arc::<ConstructNode>::unit(&ctx);
584 let c10 = Arc::<ConstructNode>::comp(&c8, &u9).unwrap();
585
586 let err = c10.finalize_types().unwrap_err();
588 assert!(matches!(err, types::Error::OccursCheck { .. }));
589 });
590 }
591}