Skip to main content

gemstone_rs/
bridge.rs

1use crate::{Error, Oop, Result, Session, Value};
2use std::collections::BTreeMap;
3
4pub const DEFAULT_BRIDGE_ROOT: &str = "GemStoneRsBridgeRoot";
5
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub enum BridgeKeyType {
8    String,
9    Symbol,
10}
11
12impl BridgeKeyType {
13    pub fn config_name(self) -> &'static str {
14        match self {
15            Self::String => "String",
16            Self::Symbol => "Symbol",
17        }
18    }
19}
20
21#[derive(Clone, Debug, Eq, PartialEq)]
22pub struct BridgeKey {
23    pub name: String,
24    pub key_type: BridgeKeyType,
25}
26
27impl BridgeKey {
28    pub fn string(name: impl Into<String>) -> Self {
29        Self {
30            name: name.into(),
31            key_type: BridgeKeyType::String,
32        }
33    }
34
35    pub fn symbol(name: impl Into<String>) -> Self {
36        Self {
37            name: name.into(),
38            key_type: BridgeKeyType::Symbol,
39        }
40    }
41
42    pub fn new(name: impl Into<String>, key_type: BridgeKeyType) -> Self {
43        Self {
44            name: name.into(),
45            key_type,
46        }
47    }
48
49    fn to_oop(&self, session: &mut Session) -> Result<Oop> {
50        match self.key_type {
51            BridgeKeyType::String => session.new_string(&self.name),
52            BridgeKeyType::Symbol => session.new_symbol(&self.name),
53        }
54    }
55}
56
57#[derive(Clone, Debug, PartialEq)]
58pub enum BridgeValue {
59    Nil,
60    Bool(bool),
61    SmallInt(i64),
62    String(String),
63    Symbol(String),
64    Oop(Oop),
65    Dictionary(BTreeMap<String, BridgeValue>),
66    KeyedDictionary(Vec<(BridgeKey, BridgeValue)>),
67    Array(Vec<BridgeValue>),
68}
69
70impl BridgeValue {
71    pub fn dictionary(entries: impl IntoIterator<Item = (String, BridgeValue)>) -> Self {
72        Self::Dictionary(entries.into_iter().collect())
73    }
74
75    pub fn keyed_dictionary(entries: impl IntoIterator<Item = (BridgeKey, BridgeValue)>) -> Self {
76        Self::KeyedDictionary(entries.into_iter().collect())
77    }
78
79    pub fn array(values: impl IntoIterator<Item = BridgeValue>) -> Self {
80        Self::Array(values.into_iter().collect())
81    }
82
83    pub fn to_oop(&self, session: &mut Session) -> Result<Oop> {
84        match self {
85            Self::Nil => Ok(session.nil_oop()),
86            Self::Bool(value) => Ok(session.bool_oop(*value)),
87            Self::SmallInt(value) => Ok(session.smallint_oop(*value)),
88            Self::String(value) => session.new_string(value),
89            Self::Symbol(value) => session.new_symbol(value),
90            Self::Oop(oop) => Ok(*oop),
91            Self::Dictionary(entries) => {
92                let dictionary = session.execute("Dictionary new")?;
93                session.identity_for_oop(dictionary);
94                for (key, value) in entries {
95                    let key = session.new_string(key)?;
96                    let value = value.to_oop(session)?;
97                    session.perform_oop(dictionary, "at:put:", &[key, value])?;
98                }
99                Ok(dictionary)
100            }
101            Self::KeyedDictionary(entries) => {
102                let dictionary = session.execute("Dictionary new")?;
103                session.identity_for_oop(dictionary);
104                for (key, value) in entries {
105                    let key = key.to_oop(session)?;
106                    let value = value.to_oop(session)?;
107                    session.perform_oop(dictionary, "at:put:", &[key, value])?;
108                }
109                Ok(dictionary)
110            }
111            Self::Array(values) => {
112                let array = session.execute(&format!("Array new: {}", values.len()))?;
113                session.identity_for_oop(array);
114                for (index, value) in values.iter().enumerate() {
115                    let index = session.smallint_oop((index + 1) as i64);
116                    let value = value.to_oop(session)?;
117                    session.perform_oop(array, "at:put:", &[index, value])?;
118                }
119                Ok(array)
120            }
121        }
122    }
123}
124
125impl From<bool> for BridgeValue {
126    fn from(value: bool) -> Self {
127        Self::Bool(value)
128    }
129}
130
131impl From<i64> for BridgeValue {
132    fn from(value: i64) -> Self {
133        Self::SmallInt(value)
134    }
135}
136
137impl From<i32> for BridgeValue {
138    fn from(value: i32) -> Self {
139        Self::SmallInt(i64::from(value))
140    }
141}
142
143impl From<&str> for BridgeValue {
144    fn from(value: &str) -> Self {
145        Self::String(value.to_string())
146    }
147}
148
149impl From<String> for BridgeValue {
150    fn from(value: String) -> Self {
151        Self::String(value)
152    }
153}
154
155impl From<Oop> for BridgeValue {
156    fn from(value: Oop) -> Self {
157        Self::Oop(value)
158    }
159}
160
161impl From<Value> for BridgeValue {
162    fn from(value: Value) -> Self {
163        match value {
164            Value::Nil => Self::Nil,
165            Value::Bool(value) => Self::Bool(value),
166            Value::SmallInt(value) => Self::SmallInt(value),
167            Value::Char(value) => Self::String(value.to_string()),
168            Value::String(value) => Self::String(value),
169            Value::Oop(oop) => Self::Oop(oop),
170        }
171    }
172}
173
174pub trait BridgeFieldWrite {
175    fn to_bridge_field_value(&self) -> BridgeValue;
176}
177
178impl BridgeFieldWrite for bool {
179    fn to_bridge_field_value(&self) -> BridgeValue {
180        BridgeValue::Bool(*self)
181    }
182}
183
184impl BridgeFieldWrite for i64 {
185    fn to_bridge_field_value(&self) -> BridgeValue {
186        BridgeValue::SmallInt(*self)
187    }
188}
189
190impl BridgeFieldWrite for i32 {
191    fn to_bridge_field_value(&self) -> BridgeValue {
192        BridgeValue::SmallInt(i64::from(*self))
193    }
194}
195
196impl BridgeFieldWrite for String {
197    fn to_bridge_field_value(&self) -> BridgeValue {
198        BridgeValue::String(self.clone())
199    }
200}
201
202impl BridgeFieldWrite for &str {
203    fn to_bridge_field_value(&self) -> BridgeValue {
204        BridgeValue::String((*self).to_string())
205    }
206}
207
208impl BridgeFieldWrite for Oop {
209    fn to_bridge_field_value(&self) -> BridgeValue {
210        BridgeValue::Oop(*self)
211    }
212}
213
214impl BridgeFieldWrite for BridgeValue {
215    fn to_bridge_field_value(&self) -> BridgeValue {
216        self.clone()
217    }
218}
219
220impl<T: BridgeMapped> BridgeFieldWrite for T {
221    fn to_bridge_field_value(&self) -> BridgeValue {
222        self.to_bridge_value()
223    }
224}
225
226impl<T: BridgeFieldWrite> BridgeFieldWrite for Vec<T> {
227    fn to_bridge_field_value(&self) -> BridgeValue {
228        BridgeValue::array(self.iter().map(BridgeFieldWrite::to_bridge_field_value))
229    }
230}
231
232pub trait BridgeFieldRead: Sized {
233    fn read_bridge_field(
234        dictionary: &mut BridgeDictionary<'_>,
235        key: &str,
236        key_type: BridgeKeyType,
237    ) -> Result<Self> {
238        let oop = dictionary.at_oop_with_key_type(key, key_type)?;
239        Self::read_bridge_oop(
240            dictionary.session,
241            oop,
242            &BridgeFieldContext::new(key, key_type, Self::expected_type()),
243        )
244    }
245
246    fn read_bridge_oop(
247        session: &mut Session,
248        oop: Oop,
249        context: &BridgeFieldContext,
250    ) -> Result<Self>;
251
252    fn expected_type() -> &'static str;
253}
254
255impl BridgeFieldRead for String {
256    fn read_bridge_oop(
257        session: &mut Session,
258        oop: Oop,
259        _context: &BridgeFieldContext,
260    ) -> Result<Self> {
261        session.fetch_string(oop)
262    }
263
264    fn expected_type() -> &'static str {
265        "String"
266    }
267}
268
269impl BridgeFieldRead for i64 {
270    fn read_bridge_oop(
271        _session: &mut Session,
272        oop: Oop,
273        context: &BridgeFieldContext,
274    ) -> Result<Self> {
275        oop.as_smallint()
276            .ok_or_else(|| context.unexpected(format!("OOP {}", oop.raw())))
277    }
278
279    fn expected_type() -> &'static str {
280        "SmallInt"
281    }
282}
283
284impl BridgeFieldRead for bool {
285    fn read_bridge_oop(
286        _session: &mut Session,
287        oop: Oop,
288        context: &BridgeFieldContext,
289    ) -> Result<Self> {
290        oop.as_bool()
291            .ok_or_else(|| context.unexpected(format!("OOP {}", oop.raw())))
292    }
293
294    fn expected_type() -> &'static str {
295        "Bool"
296    }
297}
298
299impl BridgeFieldRead for Oop {
300    fn read_bridge_oop(
301        session: &mut Session,
302        oop: Oop,
303        _context: &BridgeFieldContext,
304    ) -> Result<Self> {
305        session.identity_for_oop(oop);
306        Ok(oop)
307    }
308
309    fn expected_type() -> &'static str {
310        "Oop"
311    }
312}
313
314impl<T: BridgeMapped> BridgeFieldRead for T {
315    fn read_bridge_oop(
316        session: &mut Session,
317        oop: Oop,
318        _context: &BridgeFieldContext,
319    ) -> Result<Self> {
320        let mut dictionary = BridgeDictionary::from_oop(session, oop);
321        T::from_bridge_dictionary(&mut dictionary)
322    }
323
324    fn expected_type() -> &'static str {
325        "Dictionary"
326    }
327}
328
329impl<T: BridgeFieldRead> BridgeFieldRead for Vec<T> {
330    fn read_bridge_oop(
331        session: &mut Session,
332        oop: Oop,
333        context: &BridgeFieldContext,
334    ) -> Result<Self> {
335        let size = session.fetch_size(oop)?;
336        if size < 0 {
337            return Err(Error::NegativeSize(size));
338        }
339        let mut values = Vec::with_capacity(size as usize);
340        for index in 1..=size {
341            let index_oop = session.smallint_oop(index);
342            let value_oop = session.perform_oop(oop, "at:", &[index_oop])?;
343            values.push(T::read_bridge_oop(session, value_oop, context)?);
344        }
345        Ok(values)
346    }
347
348    fn expected_type() -> &'static str {
349        "Array"
350    }
351}
352
353pub struct BridgeRoot<'a> {
354    session: &'a mut Session,
355    name: String,
356    oop: Oop,
357}
358
359impl<'a> BridgeRoot<'a> {
360    pub fn new(session: &'a mut Session) -> Result<Self> {
361        Self::named(session, DEFAULT_BRIDGE_ROOT)
362    }
363
364    pub fn named(session: &'a mut Session, name: impl Into<String>) -> Result<Self> {
365        let name = name.into();
366        let oop = match session.global_get(&name) {
367            Ok(oop) if oop != session.nil_oop() => oop,
368            Ok(_) | Err(_) => {
369                let root = session.execute("Dictionary new")?;
370                session.global_put(&name, root)?;
371                root
372            }
373        };
374        session.identity_for_oop(oop);
375        Ok(Self { session, name, oop })
376    }
377
378    pub fn name(&self) -> &str {
379        &self.name
380    }
381
382    pub fn oop(&self) -> Oop {
383        self.oop
384    }
385
386    pub fn identity_id(&self) -> usize {
387        self.session.identity_for_oop(self.oop)
388    }
389
390    pub fn put(&mut self, key: &str, value: impl Into<BridgeValue>) -> Result<Oop> {
391        self.put_with_key_type(key, BridgeKeyType::String, value)
392    }
393
394    pub fn put_with_key_type(
395        &mut self,
396        key: &str,
397        key_type: BridgeKeyType,
398        value: impl Into<BridgeValue>,
399    ) -> Result<Oop> {
400        let key_oop = BridgeKey::new(key, key_type).to_oop(self.session)?;
401        let value = value.into().to_oop(self.session)?;
402        self.session
403            .perform_oop(self.oop, "at:put:", &[key_oop, value])?;
404        self.session.identity_for_oop(value);
405        Ok(value)
406    }
407
408    pub fn put_mapped(&mut self, key: &str, value: &impl BridgeMapped) -> Result<Oop> {
409        self.put(key, value.to_bridge_value())
410    }
411
412    pub fn get_oop(&mut self, key: &str) -> Result<Oop> {
413        self.get_oop_with_key_type(key, BridgeKeyType::String)
414    }
415
416    pub fn get_oop_with_key_type(&mut self, key: &str, key_type: BridgeKeyType) -> Result<Oop> {
417        let key_oop = BridgeKey::new(key, key_type).to_oop(self.session)?;
418        let oop = self.session.perform_oop(self.oop, "at:", &[key_oop])?;
419        self.session.identity_for_oop(oop);
420        Ok(oop)
421    }
422
423    pub fn get_value(&mut self, key: &str) -> Result<Value> {
424        self.get_value_with_key_type(key, BridgeKeyType::String)
425    }
426
427    pub fn get_value_with_key_type(&mut self, key: &str, key_type: BridgeKeyType) -> Result<Value> {
428        let key_oop = BridgeKey::new(key, key_type).to_oop(self.session)?;
429        self.session.perform(self.oop, "at:", &[key_oop])
430    }
431
432    pub fn get_string(&mut self, key: &str) -> Result<String> {
433        let oop = self.get_oop(key)?;
434        self.session.fetch_string(oop)
435    }
436
437    pub fn get_smallint(&mut self, key: &str) -> Result<i64> {
438        match self.get_value(key)? {
439            Value::SmallInt(value) => Ok(value),
440            other => Err(unexpected_field(key, "SmallInt", other)),
441        }
442    }
443
444    pub fn get_bool(&mut self, key: &str) -> Result<bool> {
445        match self.get_value(key)? {
446            Value::Bool(value) => Ok(value),
447            other => Err(unexpected_field(key, "Bool", other)),
448        }
449    }
450
451    pub fn get_dictionary(&mut self, key: &str) -> Result<BridgeDictionary<'_>> {
452        let oop = self.get_oop(key)?;
453        Ok(BridgeDictionary::from_oop(self.session, oop))
454    }
455
456    pub fn get_mapped<T: BridgeMapped>(&mut self, key: &str) -> Result<T> {
457        let mut dictionary = self.get_dictionary(key)?;
458        T::from_bridge_dictionary(&mut dictionary)
459    }
460
461    pub fn remove(&mut self, key: &str) -> Result<Oop> {
462        self.remove_with_key_type(key, BridgeKeyType::String)
463    }
464
465    pub fn remove_with_key_type(&mut self, key: &str, key_type: BridgeKeyType) -> Result<Oop> {
466        let key_oop = BridgeKey::new(key, key_type).to_oop(self.session)?;
467        self.session.perform_oop(
468            self.oop,
469            "removeKey:ifAbsent:",
470            &[key_oop, self.session.nil_oop()],
471        )
472    }
473
474    pub fn commit(&mut self) -> Result<()> {
475        self.session.commit()
476    }
477
478    pub fn commit_with_retry(&mut self, retries: usize) -> Result<()> {
479        self.session.commit_with_retry(retries)
480    }
481
482    pub fn transaction<T>(
483        &mut self,
484        body: impl FnOnce(&mut BridgeRoot<'_>) -> Result<T>,
485    ) -> Result<T> {
486        match body(self) {
487            Ok(value) => {
488                self.commit()?;
489                Ok(value)
490            }
491            Err(err) => {
492                let _ = self.session.abort();
493                Err(err)
494            }
495        }
496    }
497}
498
499pub struct BridgeDictionary<'a> {
500    pub(crate) session: &'a mut Session,
501    oop: Oop,
502}
503
504impl<'a> BridgeDictionary<'a> {
505    pub fn from_oop(session: &'a mut Session, oop: Oop) -> Self {
506        session.identity_for_oop(oop);
507        Self { session, oop }
508    }
509
510    pub fn oop(&self) -> Oop {
511        self.oop
512    }
513
514    pub fn identity_id(&self) -> usize {
515        self.session.identity_for_oop(self.oop)
516    }
517
518    pub fn put(&mut self, key: &str, value: impl Into<BridgeValue>) -> Result<Oop> {
519        self.put_with_key_type(key, BridgeKeyType::String, value)
520    }
521
522    pub fn put_with_key_type(
523        &mut self,
524        key: &str,
525        key_type: BridgeKeyType,
526        value: impl Into<BridgeValue>,
527    ) -> Result<Oop> {
528        let key_oop = BridgeKey::new(key, key_type).to_oop(self.session)?;
529        let value = value.into().to_oop(self.session)?;
530        self.session
531            .perform_oop(self.oop, "at:put:", &[key_oop, value])?;
532        self.session.identity_for_oop(value);
533        Ok(value)
534    }
535
536    pub fn at_oop(&mut self, key: &str) -> Result<Oop> {
537        self.at_oop_with_key_type(key, BridgeKeyType::String)
538    }
539
540    pub fn at_oop_with_key_type(&mut self, key: &str, key_type: BridgeKeyType) -> Result<Oop> {
541        let key_oop = BridgeKey::new(key, key_type).to_oop(self.session)?;
542        let oop = self.session.perform_oop(self.oop, "at:", &[key_oop])?;
543        self.session.identity_for_oop(oop);
544        Ok(oop)
545    }
546
547    pub fn at_value(&mut self, key: &str) -> Result<Value> {
548        self.at_value_with_key_type(key, BridgeKeyType::String)
549    }
550
551    pub fn at_value_with_key_type(&mut self, key: &str, key_type: BridgeKeyType) -> Result<Value> {
552        let key_oop = BridgeKey::new(key, key_type).to_oop(self.session)?;
553        self.session.perform(self.oop, "at:", &[key_oop])
554    }
555
556    pub fn at_string(&mut self, key: &str) -> Result<String> {
557        self.at_string_with_key_type(key, BridgeKeyType::String)
558    }
559
560    pub fn at_string_with_key_type(
561        &mut self,
562        key: &str,
563        key_type: BridgeKeyType,
564    ) -> Result<String> {
565        let oop = self.at_oop_with_key_type(key, key_type)?;
566        self.session.fetch_string(oop)
567    }
568
569    pub fn at_smallint(&mut self, key: &str) -> Result<i64> {
570        self.at_smallint_with_key_type(key, BridgeKeyType::String)
571    }
572
573    pub fn at_smallint_with_key_type(&mut self, key: &str, key_type: BridgeKeyType) -> Result<i64> {
574        match self.at_value_with_key_type(key, key_type)? {
575            Value::SmallInt(value) => Ok(value),
576            other => Err(unexpected_field(key, "SmallInt", other)),
577        }
578    }
579
580    pub fn at_bool(&mut self, key: &str) -> Result<bool> {
581        self.at_bool_with_key_type(key, BridgeKeyType::String)
582    }
583
584    pub fn at_bool_with_key_type(&mut self, key: &str, key_type: BridgeKeyType) -> Result<bool> {
585        match self.at_value_with_key_type(key, key_type)? {
586            Value::Bool(value) => Ok(value),
587            other => Err(unexpected_field(key, "Bool", other)),
588        }
589    }
590
591    pub fn at_dictionary(&mut self, key: &str) -> Result<BridgeDictionary<'_>> {
592        self.at_dictionary_with_key_type(key, BridgeKeyType::String)
593    }
594
595    pub fn at_dictionary_with_key_type(
596        &mut self,
597        key: &str,
598        key_type: BridgeKeyType,
599    ) -> Result<BridgeDictionary<'_>> {
600        let oop = self.at_oop_with_key_type(key, key_type)?;
601        Ok(BridgeDictionary::from_oop(self.session, oop))
602    }
603
604    pub fn at_mapped<T: BridgeMapped>(&mut self, key: &str) -> Result<T> {
605        self.at_mapped_with_key_type(key, BridgeKeyType::String)
606    }
607
608    pub fn at_mapped_with_key_type<T: BridgeMapped>(
609        &mut self,
610        key: &str,
611        key_type: BridgeKeyType,
612    ) -> Result<T> {
613        let mut dictionary = self.at_dictionary_with_key_type(key, key_type)?;
614        T::from_bridge_dictionary(&mut dictionary)
615    }
616
617    pub fn at_vec<T: BridgeFieldRead>(&mut self, key: &str) -> Result<Vec<T>> {
618        self.at_vec_with_key_type(key, BridgeKeyType::String)
619    }
620
621    pub fn at_vec_with_key_type<T: BridgeFieldRead>(
622        &mut self,
623        key: &str,
624        key_type: BridgeKeyType,
625    ) -> Result<Vec<T>> {
626        BridgeFieldRead::read_bridge_field(self, key, key_type)
627    }
628}
629
630pub trait BridgeMapped: Sized {
631    fn to_bridge_value(&self) -> BridgeValue;
632
633    fn from_bridge_dictionary(dictionary: &mut BridgeDictionary<'_>) -> Result<Self>;
634}
635
636#[doc(hidden)]
637pub struct BridgeFieldContext {
638    key: String,
639    key_type: BridgeKeyType,
640    expected: &'static str,
641}
642
643impl BridgeFieldContext {
644    fn new(key: &str, key_type: BridgeKeyType, expected: &'static str) -> Self {
645        Self {
646            key: key.to_string(),
647            key_type,
648            expected,
649        }
650    }
651
652    fn unexpected(&self, actual: String) -> Error {
653        Error::Mapping {
654            field: format!("{} ({})", self.key, self.key_type.config_name()),
655            expected: self.expected,
656            actual,
657        }
658    }
659}
660
661fn unexpected_field(key: &str, expected: &'static str, actual: Value) -> Error {
662    Error::Mapping {
663        field: key.to_string(),
664        expected,
665        actual: format!("{actual:?}"),
666    }
667}