mod run;
pub use run::{ReportFile, ReportHost, UseEnd, run};
use crate::lir::{ConstId, ExprId, PlaceId};
use crate::vocab::Pos;
use crate::{codec_enum, codec_struct};
pub mod state {
pub const INITIATED: usize = 0;
pub const GENERATED: usize = 1;
pub const STARTED: usize = 2;
pub const HEADING_DUE: usize = 3;
pub const BODY_ON_PAGE: usize = 4;
pub const HEADING_ONLY: usize = 5;
pub const VERTICAL: usize = 8;
pub const SAVED_NEXT_GROUP: usize = 12;
pub const FLAGS: usize = 16;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Footing {
Line(u32),
Plus(u32),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NextGroup {
Line(u32),
Plus(u32),
NextPage,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LineNumber {
Line(u32),
Plus(u32),
NextPage(Option<u32>),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ColumnNumber {
Left(u32),
Plus(u32),
Right(u32),
Center(u32),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ReportOp {
Initiate(u32),
Generate { report: u32, detail: Option<u32> },
Terminate(u32),
Suppress,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Writer<X = ExprId, C = PlaceId, V = ConstId> {
pub reports: Vec<Report<X, C, V>>,
pub print_switch: Option<usize>,
}
impl<X, C, V> Default for Writer<X, C, V> {
fn default() -> Self {
Writer { reports: Vec::new(), print_switch: None }
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Report<X = ExprId, C = PlaceId, V = ConstId> {
pub name: String,
pub file: usize,
pub code: Option<V>,
pub width: usize,
pub page: Option<Page>,
pub controls: Vec<Control<C>>,
pub groups: Vec<Group<X, V>>,
pub sums: Vec<Sum>,
pub subtotals: Vec<Subtotal<X>>,
pub page_counter: usize,
pub line_counter: usize,
pub state: usize,
pub report_heading: Option<usize>,
pub page_heading: Option<usize>,
pub page_footing: Option<usize>,
pub report_footing: Option<usize>,
pub control_headings: Vec<Option<usize>>,
pub control_footings: Vec<Option<usize>>,
pub first_detail_written: Option<i64>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Page {
pub limit: i64,
pub heading: i64,
pub first_detail: i64,
pub last_detail: i64,
pub footing: i64,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Control<C = PlaceId> {
pub reference: C,
pub saved: usize,
pub len: usize,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GroupKind {
ReportHeading,
PageHeading,
ControlHeading,
Detail,
ControlFooting,
PageFooting,
ReportFooting,
}
impl GroupKind {
pub fn is_body(self) -> bool {
matches!(self, Self::ControlHeading | Self::Detail | Self::ControlFooting)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Group<X = ExprId, V = ConstId> {
pub name: Option<String>,
pub kind: GroupKind,
pub level: usize,
pub next_group: Option<NextGroup>,
pub lines: Vec<Line<X, V>>,
pub unprinted: Vec<Field<X, V>>,
pub cross: Vec<(usize, Origin<X, V>)>,
pub rolls: Vec<(usize, Origin<X, V>)>,
pub totals: Vec<usize>,
pub indicate: Option<usize>,
pub declarative: Option<(usize, usize)>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Line<X = ExprId, V = ConstId> {
pub number: LineNumber,
pub fields: Vec<Field<X, V>>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Field<X = ExprId, V = ConstId> {
pub item: usize,
pub column: usize,
pub content: FieldContent<X, V>,
pub group_indicate: bool,
pub blank_when_zero: bool,
pub rounded: bool,
pub pos: Pos,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FieldContent<X = ExprId, V = ConstId> {
Source(X),
Value(V),
Sum(usize),
Program,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Sum {
pub total: usize,
pub reset: Option<usize>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Origin<X = ExprId, V = ConstId> {
Source(X),
Value(V),
Total(usize),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Subtotal<X = ExprId> {
pub sum: usize,
pub operand: X,
pub adding: Adding,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Adding {
EveryGenerate,
Upon(Vec<usize>),
Correlated(Vec<usize>),
}
pub fn span<X, V>(g: &Group<X, V>) -> i64 {
g.lines.iter().map(|l| if let LineNumber::Plus(k) = l.number { k as i64 } else { 0 }).sum()
}
pub fn generate_target<X, C, V>(reports: &[Report<X, C, V>], name: &str, qualifier: Option<&str>) -> Option<(usize, Option<usize>)> {
if qualifier.is_none()
&& let Some(ri) = reports.iter().position(|r| r.name == name)
{
return Some((ri, None));
}
let mut found = reports
.iter()
.enumerate()
.filter(|(_, r)| qualifier.is_none_or(|q| r.name == q))
.flat_map(|(ri, r)| r.groups.iter().enumerate().filter(|(_, g)| g.kind == GroupKind::Detail && g.name.as_deref() == Some(name)).map(move |(gi, _)| (ri, Some(gi))));
let first = found.next()?;
found.next().is_none().then_some(first)
}
codec_enum!(ReportOp { Initiate(report) = 0, Generate { report, detail } = 1, Terminate(report) = 2, Suppress = 3 });
codec_enum!(NextGroup { Line(line) = 0, Plus(lines) = 1, NextPage = 2 });
codec_enum!(LineNumber { Line(line) = 0, Plus(lines) = 1, NextPage(line) = 2 });
codec_struct!(Writer { reports, print_switch });
codec_struct!(Report {
name, file, code, width, page, controls, groups, sums, subtotals, page_counter, line_counter, state, report_heading,
page_heading, page_footing, report_footing, control_headings, control_footings, first_detail_written,
});
codec_struct!(Page { limit, heading, first_detail, last_detail, footing });
codec_struct!(Control { reference, saved, len });
codec_enum!(GroupKind {
ReportHeading = 0,
PageHeading = 1,
ControlHeading = 2,
Detail = 3,
ControlFooting = 4,
PageFooting = 5,
ReportFooting = 6,
});
codec_struct!(Group { name, kind, level, next_group, lines, unprinted, cross, rolls, totals, indicate, declarative });
codec_struct!(Line { number, fields });
codec_struct!(Field { item, column, content, group_indicate, blank_when_zero, rounded, pos });
codec_enum!(FieldContent { Source(expr) = 0, Value(value) = 1, Sum(sum) = 2, Program = 3 });
codec_struct!(Sum { total, reset });
codec_enum!(Origin { Source(expr) = 0, Value(value) = 1, Total(sum) = 2 });
codec_struct!(Subtotal { sum, operand, adding });
codec_enum!(Adding { EveryGenerate = 0, Upon(details) = 1, Correlated(details) = 2 });