halfbit/data_cell/
mod.rs

1use core::fmt;
2use core::fmt::Write as FmtWrite;
3use core::ops::Deref;
4use core::cell::RefCell;
5use core::cell::BorrowError;
6use core::cell::BorrowMutError;
7use core::convert::TryInto;
8
9use crate::ExecutionContext;
10use crate::mm::AllocatorRef;
11use crate::mm::AllocError;
12use crate::mm::Rc;
13use crate::mm::Vector;
14use crate::io::IOError;
15use crate::io::IOPartialError;
16use crate::io::ErrorCode;
17use crate::io::stream::Write;
18use crate::io::stream::SeekFrom;
19use crate::io::stream::Stream;
20use crate::num::fmt as num_fmt;
21
22pub mod expr;
23pub mod eval;
24pub mod content_stream;
25
26/* Error ********************************************************************/
27#[derive(Debug, PartialEq)]
28pub enum Error<'e> {
29    NotApplicable,
30    Alloc(AllocError),
31    IO(IOError<'e>),
32    Output(IOError<'e>), // used by report-generating functions like output_as_human_readable
33    CellUnavailable, // borrow error on a RefCell while computing something
34}
35
36impl fmt::Display for Error<'_> {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        match self {
39            Error::NotApplicable => "not applicable".fmt(f),
40            Error::CellUnavailable => "data unavailable due to internal state".fmt(f),
41            Error::Alloc(v) => write!(f, "allocation error ({})", v),
42            Error::IO(v) => write!(f, "I/O error ({})", v),
43            Error::Output(v) => write!(f, "reporting output error ({})", v),
44        }
45    }
46}
47
48impl From<fmt::Error> for Error<'_> {
49    fn from (_: fmt::Error) -> Self {
50        Error::Output(
51            IOError::with_str(
52                ErrorCode::Unsuccessful,
53                "error formatting output"))
54    }
55}
56
57impl From<BorrowError> for Error<'_> {
58    fn from(_: BorrowError) -> Self {
59        Error::CellUnavailable
60    }
61}
62
63impl From<BorrowMutError> for Error<'_> {
64    fn from(_: BorrowMutError) -> Self {
65        Error::CellUnavailable
66    }
67}
68
69impl From<AllocError> for Error<'_> {
70    fn from(e: AllocError) -> Self {
71        Error::Alloc(e)
72    }
73}
74
75impl<T> From<(AllocError, T)> for Error<'_> {
76    fn from(e: (AllocError, T)) -> Self {
77        Error::Alloc(e.0)
78    }
79}
80
81impl<'a> From<IOPartialError<'a>> for Error<'a> {
82    fn from(src: IOPartialError<'a>) -> Self {
83        Error::IO(src.to_error())
84    }
85}
86
87impl<'a> From<IOError<'a>> for Error<'a> {
88    fn from(src: IOError<'a>) -> Self {
89        Error::IO(src)
90    }
91}
92
93pub fn output_byte_slice_as_human_readable_text<'w, 'x>(
94    data: &[u8],
95    out: &mut (dyn Write + 'w),
96    _xc: &mut ExecutionContext<'x>
97) -> Result<(), Error<'x>> {
98    for &b in data {
99        if b == 0x22 || b == 0x5C {
100            write!(out, "\\{}", b as char)?;
101        } else if b >= 0x20_u8 && b <= 0x7E_u8 {
102            write!(out, "{}", b as char)?;
103        } else {
104            write!(out, "\\x{:02X}", b)?;
105        }
106    }
107    Ok(())
108}
109
110/* DataCellOpsMut ***********************************************************/
111pub trait DataCellOpsMut: fmt::Debug {
112
113    fn get_property_mut<'x>(
114        &mut self,
115        _property_name: &str,
116        _xc: &mut ExecutionContext<'x>,
117    ) -> Result<DataCell<'x>, Error<'x>> {
118        Err(Error::NotApplicable)
119    }
120
121    fn output_as_human_readable_mut<'w, 'x>(
122        &mut self,
123        _out: &mut (dyn Write + 'w),
124        _xc: &mut ExecutionContext<'x>,
125    ) -> Result<(), Error<'x>> {
126        Err(Error::NotApplicable)
127    }
128
129}
130
131/* DataCellOps **************************************************************/
132pub trait DataCellOps: fmt::Debug {
133
134    fn get_property<'x>(
135        &self,
136        _property_name: &str,
137        _xc: &mut ExecutionContext<'x>,
138    ) -> Result<DataCell<'x>, Error<'x>> {
139        Err(Error::NotApplicable)
140    }
141
142    fn output_as_human_readable<'w, 'x>(
143        &self,
144        _out: &mut (dyn Write + 'w),
145        _xc: &mut ExecutionContext<'x>,
146    ) -> Result<(), Error<'x>> {
147        Err(Error::NotApplicable)
148    }
149
150}
151
152impl<T> DataCellOps for RefCell<T>
153where T: DataCellOpsMut {
154
155    fn get_property<'x>(
156        &self,
157        property_name: &str,
158        xc: &mut ExecutionContext<'x>,
159    ) -> Result<DataCell<'x>, Error<'x>> {
160        let mut c = self.try_borrow_mut()?;
161        c.get_property_mut(property_name, xc)
162    }
163
164    fn output_as_human_readable<'w, 'x>(
165        &self,
166        out: &mut (dyn Write + 'w),
167        xc: &mut ExecutionContext<'x>,
168    ) -> Result<(), Error<'x>> {
169        let mut c = self.try_borrow_mut()?;
170        c.output_as_human_readable_mut(out, xc)
171    }
172
173}
174
175impl<'a, T> DataCellOps for Rc<'a, T>
176where T: DataCellOps {
177
178    fn get_property<'x>(
179        &self,
180        property_name: &str,
181        xc: &mut ExecutionContext<'x>,
182    ) -> Result<DataCell<'x>, Error<'x>> {
183        let c = self.as_ref();
184        c.get_property(property_name, xc)
185    }
186
187    fn output_as_human_readable<'w, 'x>(
188        &self,
189        out: &mut (dyn Write + 'w),
190        xc: &mut ExecutionContext<'x>,
191    ) -> Result<(), Error<'x>> {
192        let c = self.as_ref();
193        c.output_as_human_readable(out, xc)
194    }
195
196}
197
198/* U64Cell ******************************************************************/
199#[derive(Debug)]
200pub struct U64Cell {
201    pub n: u64,
202    pub fmt_pack: num_fmt::MiniNumFmtPack,
203}
204
205impl U64Cell {
206
207    pub fn new(n: u64) -> Self {
208        let fmt_pack = num_fmt::MiniNumFmtPack::default();
209        U64Cell { n, fmt_pack }
210    }
211    pub fn with_fmt(n: u64, fmt_pack: num_fmt::MiniNumFmtPack) -> Self {
212        U64Cell { n, fmt_pack }
213    }
214    pub fn hex(n: u64) -> Self {
215        let fmt_pack = num_fmt::MiniNumFmtPack::new(
216            num_fmt::Radix::new(16).unwrap(),
217            num_fmt::RadixNotation::DefaultPrefix,
218            num_fmt::MinDigitCount::new(2).unwrap(),
219            num_fmt::PositiveSign::Hidden,
220            num_fmt::ZeroSign::Hidden);
221        U64Cell::with_fmt(n, fmt_pack)
222    }
223}
224
225impl DataCellOps for U64Cell {
226
227    fn output_as_human_readable<'w, 'x>(
228        &self,
229        w: &mut (dyn Write + 'w),
230        xc: &mut ExecutionContext<'x>,
231    ) -> Result<(), Error<'x>> {
232        let mut buf = [0_u8; 256];
233        w.write_all(
234            self.fmt_pack.int_fmt(self.n, &mut buf).unwrap().as_bytes(),
235            xc
236        ).map_err(|e| Error::Output(e.to_error()))
237    }
238
239}
240
241/* ByteVector ***************************************************************/
242#[derive(Debug)]
243pub struct ByteVector<'a>(pub Vector<'a, u8>);
244
245impl<'a> ByteVector<'a> {
246    pub fn from_byte_slice(
247        allocator: AllocatorRef<'a>,
248        data: &[u8]
249    ) -> Result<Self, AllocError> {
250        Vector::from_slice(data, allocator).map(|bv| ByteVector(bv))
251    }
252
253}
254impl<'a> DataCellOpsMut for ByteVector<'a> {
255
256    fn get_property_mut<'x>(
257        &mut self,
258        property_name: &str,
259        _xc: &mut ExecutionContext<'x>,
260    ) -> Result<DataCell<'x>, Error<'x>> {
261        match property_name {
262            "len" | "length" | "count" | "size" => {
263                let v = self.0.len().try_into().unwrap();
264                Ok(DataCell::U64(U64Cell::new(v)))
265            },
266            _ => Err(Error::NotApplicable)
267        }
268    }
269
270    fn output_as_human_readable_mut<'w, 'x>(
271        &mut self,
272        out: &mut (dyn Write + 'w),
273        xc: &mut ExecutionContext<'x>,
274    ) -> Result<(), Error<'x>> {
275        write!(out, "b\"")?;
276        output_byte_slice_as_human_readable_text(self.0.as_slice(), out, xc)?;
277        write!(out, "\"")?;
278        Ok(())
279    }
280
281}
282
283/* DCOVector ****************************************************************/
284#[derive(Debug)]
285pub struct DCOVector<'a, T: DataCellOps>(pub Vector<'a, T>);
286
287impl<'a, T: DataCellOps> DataCellOpsMut for DCOVector<'a, T> {
288
289    fn get_property_mut<'x>(
290        &mut self,
291        property_name: &str,
292        _xc: &mut ExecutionContext<'x>,
293    ) -> Result<DataCell<'x>, Error<'x>> {
294        match property_name {
295            "len" | "length" | "count" => {
296                let v = self.0.len().try_into().unwrap();
297                Ok(DataCell::U64(U64Cell::new(v)))
298            },
299            _ => Err(Error::NotApplicable)
300        }
301    }
302
303    fn output_as_human_readable_mut<'w, 'x>(
304        &mut self,
305        out: &mut (dyn Write + 'w),
306        xc: &mut ExecutionContext<'x>,
307    ) -> Result<(), Error<'x>> {
308        write!(out, "[")?;
309        for cell in self.0.as_slice() {
310            cell.output_as_human_readable(out, xc)?;
311        }
312        write!(out, "]")?;
313        Ok(())
314    }
315
316}
317
318/* Record *******************************************************************/
319#[derive(Debug)]
320pub struct RecordDesc<'a> {
321    field_names: &'a [&'a str],
322    record_name: &'a str,
323}
324
325impl<'a> RecordDesc<'a> {
326
327    pub const fn new(
328        record_name: &'a str,
329        field_names: &'a [&'a str],
330    ) -> RecordDesc<'a> {
331        RecordDesc { field_names, record_name }
332    }
333
334    pub fn field_count(&self) -> usize {
335        self.field_names.len()
336    }
337
338    pub fn field_index(&self, name: &str) -> Option<usize> {
339        for (i, n) in self.field_names.iter().enumerate() {
340            if *n == name {
341                return Some(i);
342            }
343        }
344        None
345    }
346}
347
348#[derive(Debug)]
349pub struct Record<'a> {
350    data: Vector<'a, DataCell<'a>>,
351    desc: &'a RecordDesc<'a>,
352}
353
354impl<'a> Record<'a> {
355
356    pub fn new(
357        desc: &'a RecordDesc<'a>,
358        allocator: AllocatorRef<'a>,
359    ) -> Result<Self, AllocError> {
360        let mut data: Vector<'a, DataCell<'a>> = Vector::new(allocator);
361        let n = desc.field_count();
362        data.reserve(n)?;
363        for _i in 0..n {
364            data.push(DataCell::Nothing).unwrap();
365        }
366        Ok(Record { data, desc })
367    }
368
369    pub fn get_fields_mut<'b>(&'b mut self) -> &'b mut [DataCell<'a>] {
370        self.data.as_mut_slice()
371    }
372
373    pub fn set_field(&mut self, name: &str, value: DataCell<'a>) {
374        self.data.as_mut_slice()[self.desc.field_index(name).unwrap()] = value;
375    }
376}
377
378impl<'a> DataCellOpsMut for Record<'a> {
379
380    fn get_property_mut<'x>(
381        &mut self,
382        _property_name: &str,
383        _xc: &mut ExecutionContext<'x>,
384    ) -> Result<DataCell<'x>, Error<'x>> {
385        Err(Error::NotApplicable)
386    }
387
388    fn output_as_human_readable_mut<'w, 'x>(
389        &mut self,
390        out: &mut (dyn Write + 'w),
391        xc: &mut ExecutionContext<'x>,
392    ) -> Result<(), Error<'x>> {
393        out.write_all(self.desc.record_name.as_bytes(), xc)?;
394        out.write_all(b"(", xc)?;
395        let v = self.data.as_slice();
396        let mut first = true;
397        for i in 0..self.desc.field_names.len() {
398            if v[i].is_nothing() { continue; }
399            if first {
400                first = false;
401            } else {
402                out.write_all(b", ", xc)?;
403            }
404            out.write_all(self.desc.field_names[i].as_bytes(), xc)?;
405            out.write_all(b": ", xc)?;
406            v[i].output_as_human_readable(out, xc)?;
407        }
408        out.write_all(b")", xc)?;
409        Ok(())
410    }
411}
412
413/* DataCell *****************************************************************/
414#[derive(Debug)]
415pub enum DataCell<'d> {
416    Nothing,
417    U64(U64Cell),
418    ByteVector(Rc<'d, RefCell<ByteVector<'d>>>),
419    StaticId(&'d str),
420    Dyn(Rc<'d, dyn DataCellOps + 'd>),
421    CellVector(Rc<'d, RefCell<DCOVector<'d, DataCell<'d>>>>),
422    Record(Rc<'d, RefCell<Record<'d>>>),
423    ByteStream(Rc<'d, RefCell<dyn Stream + 'd>>),
424}
425
426impl<'d> DataCell<'d> {
427
428    pub fn is_nothing(&self) -> bool {
429        match self {
430            DataCell::Nothing => true,
431            _ => false
432        }
433    }
434
435    pub fn new() -> Self {
436        DataCell::Nothing
437    }
438
439    pub fn from_u64_cell(n: U64Cell) -> Self {
440        DataCell::U64(n)
441    }
442    pub fn from_u64(n: u64) -> Self {
443        Self::from_u64_cell(U64Cell::new(n))
444    }
445
446    pub fn from_static_id(s: &'d str) -> Self {
447        DataCell::StaticId(s)
448    }
449
450    pub fn from_byte_slice(
451        allocator: AllocatorRef<'d>,
452        data: &[u8],
453    ) -> Result<Self, AllocError> {
454        Ok(DataCell::ByteVector(Rc::new(allocator, RefCell::new(ByteVector::from_byte_slice(allocator, data)?))?))
455    }
456}
457
458impl<'d> DataCellOps for DataCell<'d> {
459
460    fn get_property<'x>(
461        &self,
462        property_name: &str,
463        xc: &mut ExecutionContext<'x>,
464    ) -> Result<DataCell<'x>, Error<'x>> {
465        match self {
466            DataCell::U64(v) => v.get_property(property_name, xc),
467            DataCell::ByteVector(v) => v.get_property(property_name, xc),
468            DataCell::CellVector(v) => v.get_property(property_name, xc),
469            DataCell::Dyn(o) => o.get_property(property_name, xc),
470            _ => Err(Error::NotApplicable)
471        }
472    }
473
474    fn output_as_human_readable<'w, 'x>(
475        &self,
476        w: &mut (dyn Write + 'w),
477        xc: &mut ExecutionContext<'x>,
478    ) -> Result<(), Error<'x>> {
479        match self {
480            DataCell::Nothing => Ok(()),
481            DataCell::U64(v) => v.output_as_human_readable(w, xc),
482            DataCell::ByteVector(v) => v.output_as_human_readable(w, xc),
483            DataCell::StaticId(s) => {
484                w.write_all(s.as_bytes(), xc)
485                    .map_err(|e| Error::Output(e.to_error()))
486            },
487            DataCell::Dyn(v) => v.deref().output_as_human_readable(w, xc),
488            DataCell::CellVector(v) => v.deref().output_as_human_readable(w, xc),
489            DataCell::Record(v) => v.deref().output_as_human_readable(w, xc),
490            DataCell::ByteStream(_v) => panic!(),
491        }
492    }
493
494}
495
496impl<T: Stream> DataCellOpsMut for T {
497
498    fn get_property_mut<'x>(
499        &mut self,
500        _property_name: &str,
501        _xc: &mut ExecutionContext<'x>,
502    ) -> Result<DataCell<'x>, Error<'x>> {
503        Err(Error::NotApplicable)
504    }
505
506    fn output_as_human_readable_mut<'w, 'x>(
507        &mut self,
508        out: &mut (dyn Write + 'w),
509        xc: &mut ExecutionContext<'x>,
510    ) -> Result<(), Error<'x>> {
511        self.seek(SeekFrom::Start(0), xc)?;
512        out.write_all(b"b\"", xc)?;
513        let mut buf = [0_u8; 1024];
514        loop {
515            let chunk_size = self.read_uninterrupted(&mut buf, xc)?;
516            if chunk_size == 0 { break; }
517            output_byte_slice_as_human_readable_text(&buf[0..chunk_size], out, xc)?;
518        }
519        out.write_all(b"\"", xc)?;
520
521        Ok(())
522    }
523
524}
525
526#[cfg(test)]
527mod tests {
528    use super::*;
529
530    #[derive(Debug)]
531    struct Abc();
532    impl fmt::Display for Abc {
533        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
534            write!(f, "<abc>")
535        }
536    }
537    impl DataCellOps for Abc{}
538
539    #[test]
540    fn data_cell_nothing_get_property() {
541        let mut xc = ExecutionContext::nop();
542        assert_eq!(Error::NotApplicable, DataCell::Nothing.get_property("zilch", &mut xc).unwrap_err());
543    }
544
545    #[test]
546    fn default_get_property() {
547        let mut xc = ExecutionContext::nop();
548        assert_eq!(Error::NotApplicable, Abc().get_property("zilch", &mut xc).unwrap_err());
549    }
550
551    #[test]
552    fn record_human_readable() {
553        use crate::mm::{ Allocator, BumpAllocator };
554        let mut buffer = [0_u8; 1000];
555        let a = BumpAllocator::new(&mut buffer);
556        let mut xc = ExecutionContext::with_allocator_and_logless(a.to_ref());
557        let desc = RecordDesc::new("Rectangle", &["width", "height", "mode"]);
558        let mut r = Record::new(&desc, a.to_ref()).unwrap();
559
560        {
561            let mut o = xc.byte_vector();
562            r.output_as_human_readable_mut(&mut o, &mut xc).unwrap();
563            assert_eq!(core::str::from_utf8(o.as_slice()).unwrap(), "Rectangle()");
564        }
565
566        {
567            r.data.as_mut_slice()[1] = DataCell::from_u64(5);
568            let mut o = xc.byte_vector();
569            r.output_as_human_readable_mut(&mut o, &mut xc).unwrap();
570            assert_eq!(core::str::from_utf8(o.as_slice()).unwrap(),
571                       "Rectangle(height: 5)");
572        }
573
574        {
575            r.data.as_mut_slice()[1] = DataCell::from_u64(7);
576            r.data.as_mut_slice()[2] = DataCell::from_static_id("FUNKY");
577            let mut o = xc.byte_vector();
578            r.output_as_human_readable_mut(&mut o, &mut xc).unwrap();
579            assert_eq!(core::str::from_utf8(o.as_slice()).unwrap(),
580                       "Rectangle(height: 7, mode: FUNKY)");
581        }
582
583        {
584            r.data.as_mut_slice()[0] = DataCell::from_u64(8);
585            r.data.as_mut_slice()[1] = DataCell::new();
586            r.data.as_mut_slice()[2] = DataCell::from_static_id("CHECKERED");
587            let mut o = xc.byte_vector();
588            r.output_as_human_readable_mut(&mut o, &mut xc).unwrap();
589            assert_eq!(core::str::from_utf8(o.as_slice()).unwrap(),
590                       "Rectangle(width: 8, mode: CHECKERED)");
591        }
592
593        {
594            r.data.as_mut_slice()[0] = DataCell::from_u64(9);
595            let nf = num_fmt::MiniNumFmtPack::new(
596                num_fmt::Radix::new(16).unwrap(),
597                num_fmt::RadixNotation::DefaultPrefix,
598                num_fmt::MinDigitCount::new(2).unwrap(),
599                num_fmt::PositiveSign::Plus,
600                num_fmt::ZeroSign::Space);
601            r.data.as_mut_slice()[1] = DataCell::from_u64_cell(U64Cell::with_fmt(10, nf));
602            r.data.as_mut_slice()[2] = DataCell::from_static_id("WEIRDO");
603            let mut o = xc.byte_vector();
604            r.output_as_human_readable_mut(&mut o, &mut xc).unwrap();
605            assert_eq!(core::str::from_utf8(o.as_slice()).unwrap(),
606                       "Rectangle(width: 9, height: +0x0A, mode: WEIRDO)");
607        }
608    }
609}
610