Skip to main content

Table

Struct Table 

Source
pub struct Table { /* private fields */ }
Expand description

A bounded table of typed rows - the canonical structured-pipe value. Owned column names (so a from_json parse can name columns dynamically), rows of Value, and a byte arena holding the Str cells. All inline, no heap.

Implementations§

Source§

impl Table

Source

pub fn new(cols: &[&str]) -> Table

A new table with the given column names (in order).

Source

pub fn add_col(&mut self, name: &[u8]) -> Option<usize>

Add a column by name; returns its index (or None if full / name too long → overflow).

Source

pub fn intern(&mut self, s: &[u8]) -> Value

Copy bytes into the arena and return a Str value (or Empty if the arena is full).

Source

pub fn add_row(&mut self, vals: &[Value])

Append a row (values in column order). Loud-bounded: extra rows set Table::overflow.

Source

pub fn ncols(&self) -> usize

Number of columns.

Source

pub fn nrows(&self) -> usize

Number of rows.

Source

pub fn cell_int(&self, r: usize, c: usize) -> Option<u64>

The value of a numeric cell; None for a string or absent one. The twin of Table::cell_bytes, for the same reason: deriving a view from a table beats rendering it and parsing the text back.

Source

pub fn cell_bytes(&self, r: usize, c: usize) -> &[u8]

The bytes of a string cell; empty for a numeric or absent one.

Exists so one table can be DERIVED from another - events deps reads the event table to count what a service actually called. Without it the only way to consume a Table was to render it and re-parse the text, which is the round-trip this record model exists to avoid.

Source

pub fn overflow(&self) -> bool

True if any bound was exceeded while building (rows/cols/arena/name).

Source

pub fn col_name(&self, c: usize) -> &[u8]

Column c’s name bytes.

Source

pub fn filter(&mut self, col: &str, op: &str, val: &str) -> bool

Keep only rows whose column col satisfies <op> val (in place). Ops: =/== != > < >= <= ~(contains). Numeric when both sides parse as numbers, else textual. Returns false (table unchanged) if col is not a column. Keep rows matching col op val. Returns false if col is not a column - and in that case the table is EMPTIED, not left alone.

It used to be left alone, so where peeer contains reply printed a notice and then handed the whole table onward: a mistyped column produced output identical to “everything matched”, and a | count downstream reported the full count. A predicate that could not be evaluated has not selected anything, and saying so with zero rows is the honest answer (invariant 12) - the loud notice stays, but it is no longer contradicted by the data underneath it.

Source

pub fn select(&mut self, names: &[&str]) -> bool

Keep only the named columns, in the given order (in place). Returns false (table unchanged) if any name is not a column. The arena (string storage) is untouched.

Source

pub fn sort(&mut self, col: &str, reverse: bool) -> bool

Order rows by column col (numeric when both ints, else by bytes), descending if reverse. Returns false (table unchanged) if col is not a column.

Source

pub fn aggregate(&self, col: &str, op: AggOp) -> Result<i128, AggErr>

Reduce a numeric column to a scalar (§5). Loud: NoColumn if col is not a column, NonNumeric if any cell is not a number - never a silent 0. Empty table reduces to 0. avg is integer, truncated toward zero. Signed columns reduce too (wifi list | max dbm is the strongest signal), which is why the result is wide.

Source

pub fn to_grid(&self, out: &mut impl RecordSink)

Render as an aligned text grid (the default view). String cells render in full (via the arena), so a long value is never silently clipped (§3.12).

Source

pub fn grid_widths(&self) -> [usize; 8]

Column widths for the grid rendering, computed over EVERY row.

Split out so a caller can render rows one at a time. A pager scrolling a long table needs the columns to stay put between frames, which means the widths must come from the whole table and not from the slice currently on screen.

Source

pub fn grid_header(&self, out: &mut impl RecordSink, w: &[usize; 8])

The grid header line, at the widths from Table::grid_widths.

Source

pub fn grid_row(&self, out: &mut impl RecordSink, r: usize, w: &[usize; 8])

One row of the grid, at the widths from Table::grid_widths. An out-of-range r writes nothing, so a pager asking past the end gets a blank line rather than a panic.

Source

pub fn to_json(&self, out: &mut impl RecordSink)

Render as a JSON array of objects (to json). Values are plain ASCII today - a real string-escaper is a documented follow-up.

Source

pub fn to_yaml(&self, out: &mut impl RecordSink)

Render as YAML - a list of mappings (to yaml). String cells render in full.

Source

pub fn from_json(input: &[u8]) -> Result<Table, &'static str>

Parse a JSON array of flat objects into a Table - the from json bridge. Bounded subset: [ {"k": v, …}, … ] with string / number / true|false / null values, no nesting. The first object defines the columns; later objects fill known columns (new keys ignored). On malformed input, returns Err(reason) with a bare static reason (the caller adds any from json: prefix).

Source

pub fn encode(&self, out: &mut impl RecordSink)

Encode the table into a compact, bounded binary form for crossing a service boundary as records (no JSON round-trip). This is emphatically not JSON - it is the Table itself on the wire. Layout:

magic "GSR1" | ncols:u8 | nrows:u8
per column:  name_len:u8 | name bytes
per cell:    tag:u8 (0=empty 1=int 2=str 3=signed)
             int → val:u64-le ; str → len:u16-le | bytes ; empty → (nothing)

Symmetric with Table::decode. The whole encoding is bounded by the table’s own bounds; a producer sends it as one IPC message (≤ 4 KiB) for a small table, or chunks it

  • the shell drains chunks until EOT, then decodes. (A chunked producer must never emit a lone 0x04 chunk, which is the EOT marker; the magic guarantees the first chunk is not.)
Source

pub fn decode(bytes: &[u8]) -> Result<Table, &'static str>

Decode the binary form produced by Table::encode. Validates the magic and every length against the table bounds and the buffer end - a truncated, oversized, or non-record buffer is a loud Err, never a misparse (§3.12). Strings intern into the new table’s arena.

Auto Trait Implementations§

§

impl Freeze for Table

§

impl RefUnwindSafe for Table

§

impl Send for Table

§

impl Sync for Table

§

impl Unpin for Table

§

impl UnsafeUnpin for Table

§

impl UnwindSafe for Table

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.