Skip to main content

sim_lib_sequence/
profile.rs

1use std::sync::Arc;
2
3use sim_kernel::{
4    CORE_SEQUENCE_CLASS_ID, ClassRef, Cx, Object, ObjectCompat, Result, Sequence, SequenceItem,
5    Symbol, Value, seq_close_value, seq_is_done, seq_next_value, seq_peek,
6};
7
8#[sim_citizen_derive::non_citizen(
9    reason = "profile sequence adapter; reconstruct from the profile symbol and source sequence descriptor",
10    kind = "handle",
11    descriptor = "core/Sequence"
12)]
13/// Sequence object that tags an inner sequence with a language profile.
14///
15/// A transparent adapter implementing the kernel [`Sequence`] contract by
16/// delegating to its inner sequence, letting sequence values cross language
17/// profile boundaries while carrying their originating profile.
18pub struct ProfileSequence {
19    profile: Symbol,
20    inner: Value,
21}
22
23impl ProfileSequence {
24    /// Wrap an inner sequence, tagging it with `profile`.
25    pub fn new(profile: Symbol, inner: Value) -> Self {
26        Self { profile, inner }
27    }
28
29    /// The language profile this sequence is tagged with.
30    pub fn profile(&self) -> &Symbol {
31        &self.profile
32    }
33}
34
35impl Object for ProfileSequence {
36    fn display(&self, _cx: &mut Cx) -> Result<String> {
37        Ok(format!("#<profile-sequence {}>", self.profile))
38    }
39
40    fn as_any(&self) -> &dyn std::any::Any {
41        self
42    }
43}
44
45impl ObjectCompat for ProfileSequence {
46    fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
47        cx.factory().class_stub(
48            CORE_SEQUENCE_CLASS_ID,
49            Symbol::qualified("core", "Sequence"),
50        )
51    }
52
53    fn as_sequence(&self) -> Option<&dyn Sequence> {
54        Some(self)
55    }
56}
57
58impl Sequence for ProfileSequence {
59    fn next_item(&self, cx: &mut Cx) -> Result<Option<SequenceItem>> {
60        seq_next_value(cx, &self.inner)
61    }
62
63    fn close(&self, cx: &mut Cx) -> Result<()> {
64        seq_close_value(cx, &self.inner)
65    }
66
67    fn peek_item(&self, cx: &mut Cx) -> Result<Option<SequenceItem>> {
68        match self.inner.object().as_sequence() {
69            Some(sequence) => seq_peek(cx, sequence),
70            None => Ok(None),
71        }
72    }
73
74    fn is_done(&self, cx: &mut Cx) -> Result<bool> {
75        match self.inner.object().as_sequence() {
76            Some(sequence) => seq_is_done(cx, sequence),
77            None => Ok(false),
78        }
79    }
80}
81
82/// Tag a sequence [`Value`] with a language profile via [`ProfileSequence`].
83pub fn sequence_for_profile(cx: &mut Cx, profile: Symbol, sequence: Value) -> Result<Value> {
84    cx.factory()
85        .opaque(Arc::new(ProfileSequence::new(profile, sequence)))
86}