Skip to main content

monty_types/object/
unstable.rs

1//! Representation access for bindings and transport adapters.
2//!
3//! These APIs expose the current storage of boundary values and carry no API
4//! compatibility guarantee: they may change or be removed in any release.
5//! Prefer [`MontyObject::as_ref`] and its value accessors when possible.
6
7use num_bigint::BigInt;
8
9use super::{CallArgs, MontyObject, NamedValues, ObjectRef};
10pub use crate::graph::{ClassTypeNode, GraphError, MontyGraph, MontyNode, NodeId};
11use crate::{file_mode::FileMode, os::TimeCaller};
12
13/// The owned arena, positional roots and keyword roots of a call.
14pub type CallArgsParts = (MontyGraph, Vec<NodeId>, Vec<(NodeId, NodeId)>);
15/// Borrowed call storage, without copying nodes or roots.
16pub type CallArgsPartsRef<'a> = (&'a MontyGraph, &'a [NodeId], &'a [(NodeId, NodeId)]);
17/// Mutable call storage for graph-level construction.
18pub type CallArgsPartsMut<'a> = (&'a mut MontyGraph, &'a mut Vec<NodeId>, &'a mut Vec<(NodeId, NodeId)>);
19
20/// Borrows the current arena and its root without copying.
21/// This exposes storage rather than a stable value interface.
22///
23/// ```
24/// use monty_types::{MontyObject, unstable};
25/// let value = MontyObject::int(42);
26/// let (graph, root) = unstable::graph_parts(&value);
27/// assert_eq!(graph.value(root), value.as_ref());
28/// ```
29#[must_use]
30pub fn graph_parts(value: &MontyObject) -> (&MontyGraph, NodeId) {
31    (&value.graph, value.root)
32}
33
34/// Takes the current arena and root without copying.
35/// Rebuild an edited graph with [`object_from_graph`] to check the root pairing.
36#[must_use]
37pub fn into_graph_parts(value: MontyObject) -> (MontyGraph, NodeId) {
38    (value.graph, value.root)
39}
40
41/// Pairs an arena with a root, checking the root is in range.
42pub fn object_from_graph(graph: MontyGraph, root: NodeId) -> Result<MontyObject, GraphError> {
43    MontyObject::new(graph, root)
44}
45
46/// Builds a value from a single node.
47///
48/// # Panics
49/// If the node holds child ids or otherwise fails graph validation.
50#[must_use]
51pub fn object_from_node(node: MontyNode) -> MontyObject {
52    MontyObject::leaf(node)
53}
54
55/// Borrows the stored root node, exposing its arena-relative child ids.
56#[must_use]
57pub fn root_node(value: &MontyObject) -> &MontyNode {
58    value.root_node()
59}
60
61/// Borrows the stored node of a value view, exposing its arena-relative child ids.
62#[must_use]
63pub fn node(value: ObjectRef<'_>) -> &MontyNode {
64    value.node()
65}
66
67/// Borrows another node from the view's arena.
68///
69/// # Panics
70/// If `id` is out of range; ids must come from this arena.
71#[must_use]
72pub fn child(value: ObjectRef<'_>, id: NodeId) -> ObjectRef<'_> {
73    value.child(id)
74}
75
76/// Borrows the arena and roots of a call without copying.
77#[must_use]
78pub fn call_args_parts(args: &CallArgs) -> CallArgsPartsRef<'_> {
79    (&args.graph, &args.arg_ids, &args.kwarg_ids)
80}
81
82/// Borrows call storage for graph-level construction.
83/// Restore valid roots before inspecting or transmitting the arguments.
84#[must_use]
85pub fn call_args_parts_mut(args: &mut CallArgs) -> CallArgsPartsMut<'_> {
86    (&mut args.graph, &mut args.arg_ids, &mut args.kwarg_ids)
87}
88
89/// Takes the arena and roots of a call without copying.
90#[must_use]
91pub fn into_call_args_parts(args: CallArgs) -> CallArgsParts {
92    (args.graph, args.arg_ids, args.kwarg_ids)
93}
94
95/// Builds a call from graph storage, rejecting out-of-range argument roots.
96pub fn call_args_from_parts(
97    graph: MontyGraph,
98    arg_ids: Vec<NodeId>,
99    kwarg_ids: Vec<(NodeId, NodeId)>,
100) -> Result<CallArgs, GraphError> {
101    let args = CallArgs {
102        graph,
103        arg_ids,
104        kwarg_ids,
105    };
106    args.check_roots()?;
107    Ok(args)
108}
109
110/// Borrows the arena and named roots of a feed without copying.
111#[must_use]
112pub fn named_values_parts(values: &NamedValues) -> (&MontyGraph, &[(String, NodeId)]) {
113    (&values.graph, &values.names)
114}
115
116/// Takes the arena and named roots of a feed without copying.
117#[must_use]
118pub fn into_named_values_parts(values: NamedValues) -> (MontyGraph, Vec<(String, NodeId)>) {
119    (values.graph, values.names)
120}
121
122/// Builds feed inputs from graph storage, rejecting out-of-range value roots.
123pub fn named_values_from_parts(graph: MontyGraph, names: Vec<(String, NodeId)>) -> Result<NamedValues, GraphError> {
124    let values = NamedValues { graph, names };
125    values.check_roots()?;
126    Ok(values)
127}
128
129/// Appends an argument directly to the call's arena and returns its node id.
130pub fn push_arg(args: &mut CallArgs, value: impl PushValue) -> NodeId {
131    let id = value.push_into(&mut args.graph);
132    args.arg_ids.push(id);
133    id
134}
135
136/// Appends a keyword argument directly to the call's arena.
137pub fn push_kwarg(args: &mut CallArgs, name: &str, value: impl PushValue) {
138    let key = args.graph.push(MontyNode::String(name.to_owned()));
139    let value = value.push_into(&mut args.graph);
140    args.kwarg_ids.push((key, value));
141}
142
143/// Appends a named value directly to the feed's arena and returns its node id.
144pub fn push_named(values: &mut NamedValues, name: impl Into<String>, value: impl PushValue) -> NodeId {
145    let id = value.push_into(&mut values.graph);
146    values.names.push((name.into(), id));
147    id
148}
149
150/// Consumes `self` into a node of `graph`, returning its id.
151/// Composite values push their children first so the arena stays post-order.
152pub trait PushValue {
153    /// Appends a value with its children below it, returning its arena-relative id.
154    fn push_into(self, graph: &mut MontyGraph) -> NodeId;
155}
156
157impl PushValue for MontyNode {
158    fn push_into(self, graph: &mut MontyGraph) -> NodeId {
159        graph.push(self)
160    }
161}
162
163impl PushValue for String {
164    fn push_into(self, graph: &mut MontyGraph) -> NodeId {
165        graph.push(MontyNode::String(self))
166    }
167}
168
169impl PushValue for Vec<u8> {
170    fn push_into(self, graph: &mut MontyGraph) -> NodeId {
171        graph.push(MontyNode::Bytes(self))
172    }
173}
174
175impl PushValue for i64 {
176    fn push_into(self, graph: &mut MontyGraph) -> NodeId {
177        graph.push(MontyNode::Int(self))
178    }
179}
180
181/// Counts above `i64::MAX` cross as `BigInt`, so a host handler receives the
182/// exact value and its own cap decides what to do with it.
183impl PushValue for u64 {
184    fn push_into(self, graph: &mut MontyGraph) -> NodeId {
185        graph.push(i64::try_from(self).map_or_else(|_| MontyNode::BigInt(BigInt::from(self)), MontyNode::Int))
186    }
187}
188
189impl PushValue for u32 {
190    fn push_into(self, graph: &mut MontyGraph) -> NodeId {
191        graph.push(MontyNode::Int(i64::from(self)))
192    }
193}
194
195/// `None` crosses as Python `None`.
196impl<T: PushValue> PushValue for Option<T> {
197    fn push_into(self, graph: &mut MontyGraph) -> NodeId {
198        match self {
199            Some(value) => value.push_into(graph),
200            None => graph.push(MontyNode::None),
201        }
202    }
203}
204
205impl PushValue for bool {
206    fn push_into(self, graph: &mut MontyGraph) -> NodeId {
207        graph.push(MontyNode::Bool(self))
208    }
209}
210
211impl PushValue for FileMode {
212    fn push_into(self, graph: &mut MontyGraph) -> NodeId {
213        graph.push(MontyNode::String(self.as_str().to_owned()))
214    }
215}
216
217impl PushValue for TimeCaller {
218    fn push_into(self, graph: &mut MontyGraph) -> NodeId {
219        graph.push(MontyNode::String(self.as_str().to_owned()))
220    }
221}