1use std::{
209 any::Any,
210 collections::HashMap,
211 fmt,
212 mem::ManuallyDrop,
213 ptr::NonNull,
214 sync::{Arc, LazyLock, Mutex},
215};
216
217use by_address::ByAddress;
218use parking_lot::RwLock;
219
220use crate::{
221 exceptions::Exception,
222 gc::{Gc, GcInner, Trace},
223 proc::{Application, ContBarrier, FuncPtr, Procedure},
224 registry::{bridge, cps_bridge},
225 runtime::{Runtime, RuntimeInner},
226 symbols::Symbol,
227 value::{UnpackedValue, Value, ValueType},
228 vectors::Vector,
229};
230
231pub use scheme_rs_macros::rtd;
232
233#[derive(Trace, Clone)]
235#[repr(align(16))]
236pub struct RecordTypeDescriptor {
237 pub name: Symbol,
239 pub sealed: bool,
242 pub opaque: bool,
245 pub uid: Option<Symbol>,
249 pub rust_type: bool,
251 pub rust_parent_constructor: Option<RustParentConstructor>,
253 pub inherits: indexmap::IndexSet<ByAddress<Arc<RecordTypeDescriptor>>>,
255 pub field_index_offset: usize,
258 pub fields: Vec<Field>,
261}
262
263impl RecordTypeDescriptor {
264 pub fn is_base_record_type(&self) -> bool {
265 self.inherits.is_empty()
266 }
267
268 pub fn is_subtype_of(self: &Arc<Self>, rtd: &Arc<Self>) -> bool {
269 Arc::ptr_eq(self, rtd) || self.inherits.contains(&ByAddress(rtd.clone()))
270 }
271
272 pub fn num_fields(&self) -> usize {
273 self.fields.len()
274 + self
275 .inherits
276 .iter()
277 .map(|parent| parent.fields.len())
278 .sum::<usize>()
279 }
280}
281
282impl fmt::Debug for RecordTypeDescriptor {
283 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284 write!(
285 f,
286 "#<rtd name: {} sealed: {} opaque: {} rust: {} ",
287 self.name, self.sealed, self.opaque, self.rust_type,
288 )?;
289 if !self.inherits.is_empty() {
290 let parent = self.inherits.last().unwrap();
291 write!(f, "parent: {} ", parent.name)?;
292 }
293 write!(f, "fields: (")?;
294 for (i, field) in self.fields.iter().enumerate() {
295 if i > 0 {
296 write!(f, " ")?;
297 }
298 field.fmt(f)?;
299 }
300 write!(f, ")>")?;
301 Ok(())
302 }
303}
304
305#[derive(Trace, Clone)]
307pub enum Field {
308 Immutable(Symbol),
309 Mutable(Symbol),
310}
311
312impl Field {
313 fn parse(field: &Value) -> Result<Self, Exception> {
314 let (mutability, field_name) = field.clone().try_into()?;
315 let mutability: Symbol = mutability.try_into()?;
316 let (field_name, _) = field_name.clone().try_into()?;
317 let field_name: Symbol = field_name.try_into()?;
318 match &*mutability.to_str() {
319 "mutable" => Ok(Field::Mutable(field_name)),
320 "immutable" => Ok(Field::Immutable(field_name)),
321 _ => Err(Exception::error(
322 "mutability specifier must be mutable or immutable".to_string(),
323 )),
324 }
325 }
326
327 fn parse_fields(fields: &Value) -> Result<Vec<Self>, Exception> {
328 let fields: Vector = fields.clone().try_into()?;
329 fields.0.vec.read().iter().map(Self::parse).collect()
330 }
331
332 fn name(&self) -> Symbol {
333 match self {
334 Self::Immutable(sym) | Self::Mutable(sym) => *sym,
335 }
336 }
337}
338
339impl fmt::Debug for Field {
340 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
341 match self {
342 Self::Immutable(sym) => write!(f, "(immutable {sym})"),
343 Self::Mutable(sym) => write!(f, "(mutable {sym})"),
344 }
345 }
346}
347
348type NonGenerativeStore = LazyLock<Arc<Mutex<HashMap<Symbol, Arc<RecordTypeDescriptor>>>>>;
349
350static NONGENERATIVE: NonGenerativeStore = LazyLock::new(|| Arc::new(Mutex::new(HashMap::new())));
351
352#[bridge(
353 name = "make-record-type-descriptor",
354 lib = "(rnrs records procedural (6))"
355)]
356pub fn make_record_type_descriptor(
357 name: &Value,
358 parent: &Value,
359 uid: &Value,
360 sealed: &Value,
361 opaque: &Value,
362 fields: &Value,
363) -> Result<Vec<Value>, Exception> {
364 let uid: Option<Symbol> = if uid.is_true() {
365 Some(uid.clone().try_into()?)
366 } else {
367 None
368 };
369
370 if let Some(ref uid) = uid
373 && let Some(rtd) = NONGENERATIVE.lock().unwrap().get(uid)
374 {
375 return Ok(vec![Value::from(rtd.clone())]);
376 }
377
378 let name: Symbol = name.clone().try_into()?;
379 let parent: Option<Arc<RecordTypeDescriptor>> = parent
380 .is_true()
381 .then(|| parent.clone().try_into())
382 .transpose()?;
383 let inherits = if let Some(parent) = parent {
384 let mut inherits = parent.inherits.clone();
385 inherits.insert(ByAddress(parent));
386 inherits
387 } else {
388 indexmap::IndexSet::new()
389 };
390 let field_index_offset = inherits.last().map_or(0, |last_parent| {
391 last_parent.field_index_offset + last_parent.fields.len()
392 });
393 let sealed = sealed.is_true();
394 let opaque = opaque.is_true();
395 let fields = Field::parse_fields(fields)?;
396 let rtd = Arc::new(RecordTypeDescriptor {
397 name,
398 sealed,
399 opaque,
400 uid,
401 rust_type: false,
402 rust_parent_constructor: None,
403 inherits,
404 field_index_offset,
405 fields,
406 });
407
408 if let Some(uid) = uid {
409 NONGENERATIVE.lock().unwrap().insert(uid, rtd.clone());
410 }
411
412 Ok(vec![Value::from(rtd)])
413}
414
415#[bridge(
416 name = "record-type-descriptor?",
417 lib = "(rnrs records procedural (6))"
418)]
419pub fn record_type_descriptor_pred(obj: &Value) -> Result<Vec<Value>, Exception> {
420 Ok(vec![Value::from(
421 obj.type_of() == ValueType::RecordTypeDescriptor,
422 )])
423}
424
425#[derive(Trace, Clone)]
427pub struct RecordConstructorDescriptor {
428 parent: Option<Gc<RecordConstructorDescriptor>>,
429 rtd: Arc<RecordTypeDescriptor>,
430 protocol: Procedure,
431}
432
433impl SchemeCompatible for RecordConstructorDescriptor {
434 fn rtd() -> Arc<RecordTypeDescriptor> {
435 rtd!(name: "record-constructor-descriptor", sealed: true, opaque: true)
436 }
437}
438
439impl fmt::Debug for RecordConstructorDescriptor {
440 fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
441 Ok(())
442 }
443}
444
445fn make_default_record_constructor_descriptor(
446 runtime: Runtime,
447 rtd: Arc<RecordTypeDescriptor>,
448) -> Gc<RecordConstructorDescriptor> {
449 let parent = rtd.inherits.last().map(|parent| {
450 make_default_record_constructor_descriptor(runtime.clone(), parent.0.clone())
451 });
452 let protocol = Procedure::new(
453 runtime,
454 vec![Value::from(rtd.clone())],
455 FuncPtr::Bridge(default_protocol),
456 1,
457 false,
458 );
459 Gc::new(RecordConstructorDescriptor {
460 parent,
461 rtd,
462 protocol,
463 })
464}
465
466#[cps_bridge(
467 def = "make-record-constructor-descriptor rtd parent-constructor-descriptor protocol",
468 lib = "(rnrs records procedural (6))"
469)]
470pub fn make_record_constructor_descriptor(
471 runtime: &Runtime,
472 _env: &[Value],
473 args: &[Value],
474 _rest_args: &[Value],
475 _barrier: &mut ContBarrier,
476 k: Value,
477) -> Result<Application, Exception> {
478 let k: Procedure = k.try_into()?;
479 let [rtd, parent_rcd, protocol] = args else {
480 unreachable!();
481 };
482
483 let rtd: Arc<RecordTypeDescriptor> = rtd.clone().try_into()?;
484
485 if rtd.rust_type && rtd.rust_parent_constructor.is_none() {
486 return Err(Exception::error(format!(
487 "cannot create a record-constructor-descriptor for rust type without a constructor {}",
488 rtd.name
489 )));
490 }
491
492 let parent_rcd = if parent_rcd.is_true() {
493 let Some(parent_rtd) = rtd.inherits.last() else {
494 return Err(Exception::error("rtd is a base type"));
495 };
496 let parent_rcd = parent_rcd.try_to_rust_type::<RecordConstructorDescriptor>()?;
497 if !Arc::ptr_eq(&parent_rcd.rtd, parent_rtd) {
498 return Err(Exception::error("parent rtd does not match parent rcd"));
499 }
500 Some(parent_rcd)
501 } else if !rtd.is_base_record_type() {
502 Some(make_default_record_constructor_descriptor(
503 runtime.clone(),
504 rtd.inherits.last().unwrap().clone().0,
505 ))
506 } else {
507 None
508 };
509
510 let protocol = if protocol.is_true() {
511 protocol.clone().try_into()?
512 } else {
513 Procedure::new(
514 runtime.clone(),
515 vec![Value::from(rtd.clone())],
516 FuncPtr::Bridge(default_protocol),
517 1,
518 false,
519 )
520 };
521
522 let rcd = RecordConstructorDescriptor {
523 parent: parent_rcd,
524 rtd,
525 protocol,
526 };
527
528 Ok(Application::new(
529 k,
530 vec![Value::from(Record::from_rust_type(rcd))],
531 ))
532}
533
534#[cps_bridge(def = "record-constructor rcd", lib = "(rnrs records procedural (6))")]
535pub fn record_constructor(
536 runtime: &Runtime,
537 _env: &[Value],
538 args: &[Value],
539 _rest_args: &[Value],
540 barrier: &mut ContBarrier,
541 k: Value,
542) -> Result<Application, Exception> {
543 let [rcd] = args else {
544 unreachable!();
545 };
546 let rcd = rcd.try_to_rust_type::<RecordConstructorDescriptor>()?;
547
548 let (protocols, rtds) = rcd_to_protocols_and_rtds(&rcd);
549
550 let rust_constructor = rtds
552 .iter()
553 .rev()
554 .find(|rtd| rtd.rust_parent_constructor.is_some())
555 .map_or_else(|| Value::from(false), |rtd| Value::from(rtd.clone()));
556
557 let protocols = protocols.into_iter().map(Value::from).collect::<Vec<_>>();
558 let rtds = rtds.into_iter().map(Value::from).collect::<Vec<_>>();
559 let chain_protocols = Value::from(barrier.new_k(
560 runtime.clone(),
561 vec![Value::from(protocols), k],
562 chain_protocols,
563 1,
564 false,
565 ));
566
567 Ok(chain_constructors(
568 runtime,
569 &[Value::from(rtds), rust_constructor],
570 &[],
571 &[],
572 barrier,
573 chain_protocols,
574 ))
575}
576
577fn rcd_to_protocols_and_rtds(
578 rcd: &Gc<RecordConstructorDescriptor>,
579) -> (Vec<Procedure>, Vec<Arc<RecordTypeDescriptor>>) {
580 let (mut protocols, mut rtds) = if let Some(ref parent) = rcd.parent {
581 rcd_to_protocols_and_rtds(parent)
582 } else {
583 (Vec::new(), Vec::new())
584 };
585 protocols.push(rcd.protocol.clone());
586 rtds.push(rcd.rtd.clone());
587 (protocols, rtds)
588}
589
590pub(crate) unsafe extern "C" fn chain_protocols(
591 runtime: *mut GcInner<RwLock<RuntimeInner>>,
592 env: *const Value,
593 args: *const Value,
594 barrier: *mut ContBarrier,
595) -> *mut Application {
596 unsafe {
597 let protocols: Vector = env.as_ref().unwrap().clone().try_into().unwrap();
599 let k = env.add(1).as_ref().unwrap().clone();
601
602 let mut protocols = protocols.0.vec.read().clone();
603 let remaining_protocols = protocols.split_off(1);
604 let curr_protocol: Procedure = protocols[0].clone().try_into().unwrap();
605
606 if remaining_protocols.is_empty() {
609 return Box::into_raw(Box::new(Application::new(
610 curr_protocol,
611 vec![args.as_ref().unwrap().clone(), k.clone()],
612 )));
613 }
614
615 let new_k = barrier.as_mut().unwrap().new_k(
617 Runtime::from_raw_inc_rc(runtime),
618 vec![Value::from(remaining_protocols), k],
619 chain_protocols,
620 1,
621 false,
622 );
623
624 Box::into_raw(Box::new(Application::new(
625 curr_protocol,
626 vec![args.as_ref().unwrap().clone(), Value::from(new_k)],
627 )))
628 }
629}
630
631#[cps_bridge]
632fn chain_constructors(
633 runtime: &Runtime,
634 env: &[Value],
635 args: &[Value],
636 _rest_args: &[Value],
637 _barrier: &mut ContBarrier,
638 k: Value,
639) -> Result<Application, Exception> {
640 let k: Procedure = k.try_into()?;
641 let rtds: Vector = env[0].clone().try_into()?;
643 let rust_constructor = env[1].clone();
645 let mut rtds = rtds.0.vec.read().clone();
646 let remaining_rtds = rtds.split_off(1);
647 let curr_rtd: Arc<RecordTypeDescriptor> = rtds[0].clone().try_into()?;
648 let rtds_remain = !remaining_rtds.is_empty();
649 let num_args = curr_rtd.fields.len();
650 let env = if rtds_remain {
651 vec![Value::from(remaining_rtds), rust_constructor]
652 } else {
653 vec![Value::from(curr_rtd), rust_constructor]
654 }
655 .into_iter()
656 .chain(env[2..].iter().cloned())
658 .chain(args.iter().cloned())
660 .collect::<Vec<_>>();
661 let next_proc = Procedure::new(
662 runtime.clone(),
663 env,
664 if rtds_remain {
665 FuncPtr::Bridge(chain_constructors)
666 } else {
667 FuncPtr::Bridge(constructor)
668 },
669 num_args,
670 false,
671 );
672 Ok(Application::new(k, vec![Value::from(next_proc)]))
673}
674
675#[cps_bridge]
676fn constructor(
677 _runtime: &Runtime,
678 env: &[Value],
679 args: &[Value],
680 _rest_args: &[Value],
681 _barrier: &mut ContBarrier,
682 k: Value,
683) -> Result<Application, Exception> {
684 let k: Procedure = k.try_into()?;
685 let rtd: Arc<RecordTypeDescriptor> = env[0].clone().try_into()?;
686 let mut fields = env[2..]
689 .iter()
690 .cloned()
691 .chain(args.iter().cloned())
692 .collect::<Vec<_>>();
693 let rust_constructor = env[1].clone();
695 let (rust_parent, fields) = if rust_constructor.is_true() {
696 let rust_rtd: Arc<RecordTypeDescriptor> = rust_constructor.try_into()?;
697 let num_fields: usize = rust_rtd
698 .inherits
699 .iter()
700 .map(|parent| parent.fields.len())
701 .sum();
702 let remaining_fields = fields.split_off(num_fields + rust_rtd.fields.len());
703 (
704 Some((rust_rtd.rust_parent_constructor.unwrap().constructor)(
705 &fields,
706 )?),
707 remaining_fields,
708 )
709 } else {
710 (None, fields)
711 };
712 let record = Value::from(Record(Gc::new(RecordInner {
713 rust_parent,
714 rtd,
715 fields: fields.into_iter().map(RwLock::new).collect(),
716 })));
717 Ok(Application::new(k, vec![record]))
718}
719
720#[cps_bridge]
721fn default_protocol(
722 runtime: &Runtime,
723 env: &[Value],
724 args: &[Value],
725 _rest_args: &[Value],
726 _barrier: &mut ContBarrier,
727 k: Value,
728) -> Result<Application, Exception> {
729 let k: Procedure = k.try_into()?;
730 let rtd: Arc<RecordTypeDescriptor> = env[0].clone().try_into()?;
731 let num_args = rtd.num_fields(); let constructor = Procedure::new(
734 runtime.clone(),
735 vec![args[0].clone(), Value::from(rtd)],
736 FuncPtr::Bridge(default_protocol_constructor),
737 num_args,
738 false,
739 );
740
741 Ok(Application::new(k, vec![Value::from(constructor)]))
742}
743
744#[cps_bridge]
745fn default_protocol_constructor(
746 runtime: &Runtime,
747 env: &[Value],
748 args: &[Value],
749 _rest_args: &[Value],
750 barrier: &mut ContBarrier,
751 k: Value,
752) -> Result<Application, Exception> {
753 let constructor: Procedure = env[0].clone().try_into()?;
754 let rtd: Arc<RecordTypeDescriptor> = env[1].clone().try_into()?;
755 let mut args = args.to_vec();
756
757 let k = if let Some(parent) = rtd.inherits.last() {
758 let remaining = args.split_off(parent.num_fields());
759 Value::from(barrier.new_k(
760 runtime.clone(),
761 vec![Value::from(remaining), k],
762 call_constructor_continuation,
763 1,
764 false,
765 ))
766 } else {
767 k
768 };
769
770 args.push(k);
771 Ok(Application::new(constructor, args))
772}
773
774pub(crate) unsafe extern "C" fn call_constructor_continuation(
775 _runtime: *mut GcInner<RwLock<RuntimeInner>>,
776 env: *const Value,
777 args: *const Value,
778 _barrier: *mut ContBarrier,
779) -> *mut Application {
780 unsafe {
781 let constructor: Procedure = args.as_ref().unwrap().clone().try_into().unwrap();
782 let args: Vector = env.as_ref().unwrap().clone().try_into().unwrap();
783 let mut args = args.0.vec.read().clone();
784 let cont = env.add(1).as_ref().unwrap().clone();
785 args.push(cont);
786
787 Box::into_raw(Box::new(Application::new(constructor, args)))
789 }
790}
791
792#[derive(Trace, Clone)]
795pub struct Record(pub(crate) Gc<RecordInner>);
796
797impl Record {
798 pub fn rtd(&self) -> Arc<RecordTypeDescriptor> {
799 self.0.rtd.clone()
800 }
801
802 pub fn from_rust_type<T: SchemeCompatible>(t: T) -> Self {
805 let opaque_parent = Some(into_scheme_compatible(Gc::new(t)));
806 let rtd = T::rtd();
807 Self(Gc::new(RecordInner {
808 rust_parent: opaque_parent,
809 rtd,
810 fields: Vec::new(),
811 }))
812 }
813
814 pub fn from_rust_gc_type<T: SchemeCompatible>(t: Gc<T>) -> Self {
815 let opaque_parent = Some(into_scheme_compatible(t));
816 let rtd = T::rtd();
817 Self(Gc::new(RecordInner {
818 rust_parent: opaque_parent,
819 rtd,
820 fields: Vec::new(),
821 }))
822 }
823
824 pub fn cast<T: SchemeCompatible>(&self) -> Option<Gc<T>> {
827 let rust_parent = self.0.rust_parent.as_ref()?;
828
829 let rtd = T::rtd();
831 let mut t = rust_parent.clone();
832 while let Some(embedded) = { t.extract_embedded_record(&rtd) } {
833 t = embedded;
834 }
835
836 let t = ManuallyDrop::new(t);
837
838 let any: NonNull<GcInner<dyn Any + Send + Sync>> = t.ptr;
840 let gc_any = Gc {
841 ptr: any,
842 marker: std::marker::PhantomData,
843 };
844
845 Gc::downcast::<T>(gc_any).ok()
847 }
848
849 pub fn get_field(&self, k: usize) -> Result<Value, Exception> {
851 self.get_parent_field(&self.rtd(), k)
852 }
853
854 pub fn get_parent_field(
856 &self,
857 rtd: &Arc<RecordTypeDescriptor>,
858 k: usize,
859 ) -> Result<Value, Exception> {
860 if !self.0.rtd.is_subtype_of(rtd) {
861 Err(Exception::error(format!("not a subtype of {}", rtd.name)))
862 } else if let Some(mut t) = self.0.rust_parent.clone() {
863 while let Some(embedded) = { t.extract_embedded_record(rtd) } {
864 t = embedded;
865 }
866 t.get_field(rtd.field_index_offset + k)
867 } else {
868 Ok(self.0.fields[rtd.field_index_offset + k].read().clone())
869 }
870 }
871
872 pub fn set_field(&self, k: usize, new_value: Value) -> Result<(), Exception> {
874 self.set_parent_field(&self.rtd(), k, new_value)
875 }
876
877 pub fn set_parent_field(
879 &self,
880 rtd: &Arc<RecordTypeDescriptor>,
881 k: usize,
882 new_value: Value,
883 ) -> Result<(), Exception> {
884 if !self.0.rtd.is_subtype_of(rtd) {
885 Err(Exception::error(format!("not a subtype of {}", rtd.name)))
886 } else if let Some(mut t) = self.0.rust_parent.clone() {
887 while let Some(embedded) = { t.extract_embedded_record(rtd) } {
888 t = embedded;
889 }
890 t.set_field(rtd.field_index_offset + k, new_value)
891 } else {
892 *self.0.fields[rtd.field_index_offset + k].write() = new_value;
893 Ok(())
894 }
895 }
896}
897
898impl fmt::Debug for Record {
899 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
900 self.0.fmt(f)
901 }
902}
903
904#[derive(Trace)]
905#[repr(align(16))]
906pub(crate) struct RecordInner {
907 pub(crate) rust_parent: Option<Gc<dyn SchemeCompatible>>,
908 pub(crate) rtd: Arc<RecordTypeDescriptor>,
909 pub(crate) fields: Vec<RwLock<Value>>,
910}
911
912impl fmt::Debug for RecordInner {
913 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
914 write!(f, "#<{}", self.rtd.name)?;
915 if let Some(parent) = &self.rust_parent {
916 write!(f, "{parent:?}")?;
917 }
918 let mut field_names = self
919 .rtd
920 .inherits
921 .iter()
922 .cloned()
923 .chain(Some(ByAddress(self.rtd.clone())))
924 .flat_map(|rtd| rtd.fields.clone());
925 for field in &self.fields {
926 let field = field.read();
927 let name = field_names.next().unwrap().name();
928 write!(f, " {name}: {field:?}")?;
929 }
930 write!(f, ">")
931 }
932}
933
934pub trait SchemeCompatible: fmt::Debug + Trace + Any + Send + Sync + 'static {
936 fn rtd() -> Arc<RecordTypeDescriptor>
939 where
940 Self: Sized;
941
942 fn extract_embedded_record(
945 &self,
946 _rtd: &Arc<RecordTypeDescriptor>,
947 ) -> Option<Gc<dyn SchemeCompatible>> {
948 None
949 }
950
951 fn get_field(&self, k: usize) -> Result<Value, Exception> {
953 Err(Exception::error(format!("invalid record field: {k}")))
954 }
955
956 fn set_field(&self, k: usize, _val: Value) -> Result<(), Exception> {
958 Err(Exception::error(format!("invalid record field: {k}")))
959 }
960}
961
962pub fn into_scheme_compatible(t: Gc<impl SchemeCompatible>) -> Gc<dyn SchemeCompatible> {
968 let t = ManuallyDrop::new(t);
971 let any: NonNull<GcInner<dyn SchemeCompatible>> = t.ptr;
972 Gc {
973 ptr: any,
974 marker: std::marker::PhantomData,
975 }
976}
977
978#[derive(Copy, Clone, Debug, Trace)]
979pub struct RustParentConstructor {
980 #[trace(skip)]
981 constructor: ParentConstructor,
982}
983
984impl RustParentConstructor {
985 pub fn new(constructor: ParentConstructor) -> Self {
986 Self { constructor }
987 }
988}
989
990type ParentConstructor = fn(&[Value]) -> Result<Gc<dyn SchemeCompatible>, Exception>;
991
992pub(crate) fn is_subtype_of(val: &Value, rt: Arc<RecordTypeDescriptor>) -> Result<bool, Exception> {
993 let UnpackedValue::Record(rec) = val.clone().unpack() else {
994 return Ok(false);
995 };
996 Ok(Arc::ptr_eq(&rec.0.rtd, &rt) || rec.0.rtd.inherits.contains(&ByAddress::from(rt)))
997}
998
999#[cps_bridge]
1000fn record_predicate_fn(
1001 _runtime: &Runtime,
1002 env: &[Value],
1003 args: &[Value],
1004 _rest_args: &[Value],
1005 _barrier: &mut ContBarrier,
1006 k: Value,
1007) -> Result<Application, Exception> {
1008 let k: Procedure = k.try_into()?;
1009 let [val] = args else {
1010 unreachable!();
1011 };
1012 let rtd: Arc<RecordTypeDescriptor> = env[0].try_to_scheme_type()?;
1014 Ok(Application::new(
1015 k,
1016 vec![Value::from(is_subtype_of(val, rtd)?)],
1017 ))
1018}
1019
1020#[cps_bridge(def = "record-predicate rtd", lib = "(rnrs records procedural (6))")]
1021pub fn record_predicate(
1022 runtime: &Runtime,
1023 _env: &[Value],
1024 args: &[Value],
1025 _rest_args: &[Value],
1026 _barrier: &mut ContBarrier,
1027 k: Value,
1028) -> Result<Application, Exception> {
1029 let k: Procedure = k.try_into()?;
1030 let [rtd] = args else {
1031 unreachable!();
1032 };
1033 let pred_fn = Procedure::new(
1035 runtime.clone(),
1036 vec![rtd.clone()],
1037 FuncPtr::Bridge(record_predicate_fn),
1038 1,
1039 false,
1040 );
1041 Ok(Application::new(k, vec![Value::from(pred_fn)]))
1042}
1043
1044#[cps_bridge]
1045fn record_accessor_fn(
1046 _runtime: &Runtime,
1047 env: &[Value],
1048 args: &[Value],
1049 _rest_args: &[Value],
1050 _barrier: &mut ContBarrier,
1051 k: Value,
1052) -> Result<Application, Exception> {
1053 let k: Procedure = k.try_into()?;
1054 let [val] = args else {
1055 unreachable!();
1056 };
1057 let record: Record = val.clone().try_into()?;
1058 let rtd: Arc<RecordTypeDescriptor> = env[0].try_to_scheme_type()?;
1060 if !is_subtype_of(val, rtd.clone())? {
1061 return Err(Exception::error("not a child of this record type"));
1062 }
1063 let idx: usize = env[1].clone().try_into()?;
1064 let val = if let Some(rust_parent) = &record.0.rust_parent
1065 && rtd.rust_type
1066 {
1067 let mut t = rust_parent.clone();
1068 while let Some(embedded) = { t.extract_embedded_record(&rtd) } {
1069 t = embedded;
1070 }
1071 t.get_field(idx)?
1072 } else {
1073 record.0.fields[idx].read().clone()
1074 };
1075 if val.is_undefined() {
1076 return Err(Exception::error(format!(
1077 "failed to get field: {}, {idx}",
1078 rtd.name
1079 )));
1080 }
1081 Ok(Application::new(k, vec![val]))
1082}
1083
1084#[cps_bridge(def = "record-accessor rtd k", lib = "(rnrs records procedural (6))")]
1085pub fn record_accessor(
1086 runtime: &Runtime,
1087 _env: &[Value],
1088 args: &[Value],
1089 _rest_args: &[Value],
1090 _barrier: &mut ContBarrier,
1091 k: Value,
1092) -> Result<Application, Exception> {
1093 let k: Procedure = k.try_into()?;
1094 let [rtd, idx] = args else {
1095 unreachable!();
1096 };
1097 let rtd: Arc<RecordTypeDescriptor> = rtd.clone().try_into()?;
1098 let idx: usize = idx.clone().try_into()?;
1099 if idx >= rtd.fields.len() {
1100 return Err(Exception::error(format!(
1101 "{idx} is out of range 0..{}",
1102 rtd.fields.len()
1103 )));
1104 }
1105 let idx = idx + rtd.field_index_offset;
1106 let accessor_fn = Procedure::new(
1107 runtime.clone(),
1108 vec![Value::from(rtd), Value::from(idx)],
1109 FuncPtr::Bridge(record_accessor_fn),
1110 1,
1111 false,
1112 );
1113 Ok(Application::new(k, vec![Value::from(accessor_fn)]))
1114}
1115
1116#[cps_bridge]
1117fn record_mutator_fn(
1118 _runtime: &Runtime,
1119 env: &[Value],
1120 args: &[Value],
1121 _rest_args: &[Value],
1122 _barrier: &mut ContBarrier,
1123 k: Value,
1124) -> Result<Application, Exception> {
1125 let k: Procedure = k.try_into()?;
1126 let [rec, new_val] = args else {
1127 unreachable!();
1128 };
1129 let record: Record = rec.clone().try_into()?;
1130 let rtd: Arc<RecordTypeDescriptor> = env[0].try_to_scheme_type()?;
1132 if !is_subtype_of(rec, rtd.clone())? {
1133 return Err(Exception::error("not a child of this record type"));
1134 }
1135 let idx: usize = env[1].clone().try_into()?;
1136 if let Some(rust_parent) = &record.0.rust_parent
1137 && rtd.rust_type
1138 {
1139 let mut t = rust_parent.clone();
1140 while let Some(embedded) = { t.extract_embedded_record(&rtd) } {
1141 t = embedded;
1142 }
1143 t.set_field(idx, new_val.clone())?;
1144 } else {
1145 *record.0.fields[idx].write() = new_val.clone();
1146 }
1147 Ok(Application::new(k, vec![]))
1148}
1149
1150#[cps_bridge(def = "record-mutator rtd k", lib = "(rnrs records procedural (6))")]
1151pub fn record_mutator(
1152 runtime: &Runtime,
1153 _env: &[Value],
1154 args: &[Value],
1155 _rest_args: &[Value],
1156 _barrier: &mut ContBarrier,
1157 k: Value,
1158) -> Result<Application, Exception> {
1159 let k: Procedure = k.try_into()?;
1160 let [rtd, idx] = args else {
1161 unreachable!();
1162 };
1163 let rtd: Arc<RecordTypeDescriptor> = rtd.clone().try_into()?;
1164 let idx: usize = idx.clone().try_into()?;
1165 if idx >= rtd.fields.len() {
1166 return Err(Exception::error(format!(
1167 "{idx} is out of range {}",
1168 rtd.fields.len()
1169 )));
1170 }
1171 if matches!(rtd.fields[idx], Field::Immutable(_)) {
1172 return Err(Exception::error(format!("{idx} is immutable")));
1173 }
1174 let idx = idx + rtd.field_index_offset;
1175 let mutator_fn = Procedure::new(
1176 runtime.clone(),
1177 vec![Value::from(rtd), Value::from(idx)],
1178 FuncPtr::Bridge(record_mutator_fn),
1179 2,
1180 false,
1181 );
1182 Ok(Application::new(k, vec![Value::from(mutator_fn)]))
1183}
1184
1185#[bridge(name = "record?", lib = "(rnrs records inspection (6))")]
1188pub fn record_pred(obj: &Value) -> Result<Vec<Value>, Exception> {
1189 match &*obj.unpacked_ref() {
1190 UnpackedValue::Record(rec) => Ok(vec![Value::from(!rec.0.rtd.opaque)]),
1191 _ => Ok(vec![Value::from(false)]),
1192 }
1193}
1194
1195#[bridge(name = "record-rtd", lib = "(rnrs records inspection (6))")]
1196pub fn record_rtd(record: &Value) -> Result<Vec<Value>, Exception> {
1197 match &*record.unpacked_ref() {
1198 UnpackedValue::Record(rec) if !rec.0.rtd.opaque => Ok(vec![Value::from(rec.0.rtd.clone())]),
1199 _ => Err(Exception::error(
1200 "expected a non-opaque record type".to_string(),
1201 )),
1202 }
1203}
1204
1205#[bridge(name = "record-type-name", lib = "(rnrs records inspection (6))")]
1206pub fn record_type_name(rtd: &Value) -> Result<Vec<Value>, Exception> {
1207 let rtd: Arc<RecordTypeDescriptor> = rtd.clone().try_into()?;
1208 Ok(vec![Value::from(rtd.name)])
1209}
1210
1211#[bridge(name = "record-type-parent", lib = "(rnrs records inspection (6))")]
1212pub fn record_type_parent(rtd: &Value) -> Result<Vec<Value>, Exception> {
1213 let rtd: Arc<RecordTypeDescriptor> = rtd.clone().try_into()?;
1214 if let Some(parent) = rtd.inherits.last() {
1215 Ok(vec![Value::from(parent.0.clone())])
1216 } else {
1217 Ok(vec![Value::from(false)])
1218 }
1219}
1220
1221#[bridge(name = "record-type-uid", lib = "(rnrs records inspection (6))")]
1222pub fn record_type_uid(rtd: &Value) -> Result<Vec<Value>, Exception> {
1223 let rtd: Arc<RecordTypeDescriptor> = rtd.clone().try_into()?;
1224 if let Some(uid) = rtd.uid {
1225 Ok(vec![Value::from(uid)])
1226 } else {
1227 Ok(vec![Value::from(false)])
1228 }
1229}
1230
1231#[bridge(
1232 name = "record-type-generative?",
1233 lib = "(rnrs records inspection (6))"
1234)]
1235pub fn record_type_generative_pred(rtd: &Value) -> Result<Vec<Value>, Exception> {
1236 let rtd: Arc<RecordTypeDescriptor> = rtd.clone().try_into()?;
1237 Ok(vec![Value::from(rtd.uid.is_none())])
1238}
1239
1240#[bridge(name = "record-type-sealed?", lib = "(rnrs records inspection (6))")]
1241pub fn record_type_sealed_pred(rtd: &Value) -> Result<Vec<Value>, Exception> {
1242 let rtd: Arc<RecordTypeDescriptor> = rtd.clone().try_into()?;
1243 Ok(vec![Value::from(rtd.sealed)])
1244}
1245
1246#[bridge(name = "record-type-opaque?", lib = "(rnrs records inspection (6))")]
1247pub fn record_type_opaque_pred(rtd: &Value) -> Result<Vec<Value>, Exception> {
1248 let rtd: Arc<RecordTypeDescriptor> = rtd.clone().try_into()?;
1249 Ok(vec![Value::from(rtd.opaque)])
1250}
1251
1252#[bridge(
1253 name = "record-type-field-names",
1254 lib = "(rnrs records inspection (6))"
1255)]
1256pub fn record_type_field_names(rtd: &Value) -> Result<Vec<Value>, Exception> {
1257 let rtd: Arc<RecordTypeDescriptor> = rtd.clone().try_into()?;
1258 let fields = rtd
1259 .fields
1260 .iter()
1261 .map(Field::name)
1262 .map(Value::from)
1263 .collect::<Vec<_>>();
1264 Ok(vec![Value::from(fields)])
1265}
1266
1267#[bridge(name = "record-field-mutable?", lib = "(rnrs records inspection (6))")]
1268pub fn record_field_mutable_pred(rtd: &Value, k: &Value) -> Result<Vec<Value>, Exception> {
1269 let rtd: Arc<RecordTypeDescriptor> = rtd.clone().try_into()?;
1270 let k: usize = k.try_to_scheme_type()?;
1271
1272 if k >= rtd.fields.len() {
1273 return Err(Exception::invalid_index(k, rtd.fields.len()));
1274 }
1275
1276 Ok(vec![Value::from(matches!(
1277 rtd.fields[k],
1278 Field::Mutable(_)
1279 ))])
1280}