Skip to main content

ironwork_rt/
codec.rs

1//! A numeric item's storage read as generated code reads it. The interpreter and the SQL runtime
2//! share it, so a host variable sends exactly the value a COMPUTE would read.
3
4use numeric::Numproc;
5use crate::vocab::{SignClause, SignPosition};
6use zarch::check::ProgramCheck;
7use zarch::decimal::{self, Decimal};
8
9/// A packed field. Under NUMPROC(NOPFD) an unsigned field's sign nibble is forced to F first.
10pub fn packed(bytes: &[u8], signed: bool, numproc: Numproc) -> Result<Decimal, ProgramCheck> {
11    let mut p = bytes.to_vec();
12    if !signed && numproc == Numproc::Nopfd {
13        *p.last_mut().unwrap() |= 0x0F;
14    }
15    decimal::decode(&p)
16}
17
18/// A zoned field, entering through PACK, which keeps only the sign's zone.
19pub fn zoned(bytes: &[u8], signed: bool, sign: Option<SignClause>, numproc: Numproc) -> Result<Decimal, ProgramCheck> {
20    let mut zoned = bytes.to_vec();
21    let mut separate_negative = None;
22    match sign {
23        Some(SignClause { separate: true, position }) => {
24            let s = if position == SignPosition::Leading { zoned.remove(0) } else { zoned.pop().unwrap() };
25            separate_negative = Some(match s {
26                0x60 => true,
27                0x4E => false,
28                _ => return Err(ProgramCheck::Data),
29            });
30            *zoned.last_mut().unwrap() |= 0xF0;
31        }
32        Some(SignClause { separate: false, position: SignPosition::Leading }) => {
33            let zone = zoned[0] & 0xF0;
34            zoned[0] |= 0xF0;
35            let last = zoned.len() - 1;
36            zoned[last] = zone | (zoned[last] & 0x0F);
37        }
38        _ => {}
39    }
40    let p = numeric::zoned::pack(&zoned)?;
41    let value = packed(&p, signed, numproc)?;
42    Ok(match separate_negative {
43        Some(negative) => Decimal { negative, ..value },
44        None => value,
45    })
46}