1mod run;
9
10pub use run::{ReportFile, ReportHost, UseEnd, run};
11
12use crate::lir::{Comparand, ConstId, PlaceId, RangeId};
13use crate::vocab::Pos;
14use crate::{codec_enum, codec_struct};
15
16pub mod state {
18 pub const INITIATED: usize = 0;
19 pub const GENERATED: usize = 1;
20 pub const STARTED: usize = 2;
22 pub const HEADING_DUE: usize = 3;
24 pub const BODY_ON_PAGE: usize = 4;
25 pub const HEADING_ONLY: usize = 5;
27 pub const VERTICAL: usize = 8;
29 pub const SAVED_NEXT_GROUP: usize = 12;
31 pub const FLAGS: usize = 16;
33}
34
35#[derive(Clone, Copy, Debug, PartialEq, Eq)]
37pub enum Footing {
38 Line(u32),
39 Plus(u32),
40}
41
42#[derive(Clone, Copy, Debug, PartialEq, Eq)]
43pub enum NextGroup {
44 Line(u32),
45 Plus(u32),
46 NextPage,
47}
48
49#[derive(Clone, Copy, Debug, PartialEq, Eq)]
50pub enum LineNumber {
51 Line(u32),
52 Plus(u32),
53 NextPage(Option<u32>),
55}
56
57#[derive(Clone, Copy, Debug, PartialEq, Eq)]
58pub enum ColumnNumber {
59 Left(u32),
60 Plus(u32),
61 Right(u32),
62 Center(u32),
63}
64
65#[derive(Clone, Copy, Debug, PartialEq, Eq)]
68pub enum ReportOp {
69 Initiate(u32),
70 Generate { report: u32, detail: Option<u32> },
71 Terminate(u32),
72 Suppress,
73}
74
75#[derive(Clone, Debug, PartialEq, Eq)]
78pub struct Writer<X = Comparand, C = PlaceId, V = ConstId, U = RangeId> {
79 pub reports: Vec<Report<X, C, V, U>>,
80 pub print_switch: Option<usize>,
82}
83
84impl<X, C, V, U> Default for Writer<X, C, V, U> {
85 fn default() -> Self {
86 Writer { reports: Vec::new(), print_switch: None }
87 }
88}
89
90#[derive(Clone, Debug, PartialEq, Eq)]
91pub struct Report<X = Comparand, C = PlaceId, V = ConstId, U = RangeId> {
92 pub name: String,
93 pub file: usize,
94 pub code: Option<V>,
95 pub width: usize,
97 pub page: Option<Page>,
98 pub controls: Vec<Control<C>>,
100 pub groups: Vec<Group<X, V, U>>,
101 pub sums: Vec<Sum>,
102 pub subtotals: Vec<Subtotal<X>>,
104 pub page_counter: usize,
105 pub line_counter: usize,
106 pub state: usize,
107 pub report_heading: Option<usize>,
108 pub page_heading: Option<usize>,
109 pub page_footing: Option<usize>,
110 pub report_footing: Option<usize>,
111 pub control_headings: Vec<Option<usize>>,
113 pub control_footings: Vec<Option<usize>>,
114 pub first_detail_written: Option<i64>,
116}
117
118#[derive(Clone, Copy, Debug, PartialEq, Eq)]
120pub struct Page {
121 pub limit: i64,
122 pub heading: i64,
123 pub first_detail: i64,
124 pub last_detail: i64,
125 pub footing: i64,
126}
127
128#[derive(Clone, Debug, PartialEq, Eq)]
129pub struct Control<C = PlaceId> {
130 pub reference: C,
131 pub saved: usize,
133 pub len: usize,
134}
135
136#[derive(Clone, Copy, Debug, PartialEq, Eq)]
137pub enum GroupKind {
138 ReportHeading,
139 PageHeading,
140 ControlHeading,
141 Detail,
142 ControlFooting,
143 PageFooting,
144 ReportFooting,
145}
146
147impl GroupKind {
148 pub fn is_body(self) -> bool {
149 matches!(self, Self::ControlHeading | Self::Detail | Self::ControlFooting)
150 }
151}
152
153#[derive(Clone, Debug, PartialEq, Eq)]
154pub struct Group<X = Comparand, V = ConstId, U = RangeId> {
155 pub name: Option<String>,
156 pub kind: GroupKind,
157 pub level: usize,
159 pub next_group: Option<NextGroup>,
160 pub lines: Vec<Line<X, V>>,
161 pub unprinted: Vec<Field<X, V>>,
163 pub cross: Vec<(usize, Origin<X, V>)>,
165 pub rolls: Vec<(usize, Origin<X, V>)>,
167 pub totals: Vec<usize>,
169 pub indicate: Option<usize>,
170 pub declarative: Option<U>,
172}
173
174#[derive(Clone, Debug, PartialEq, Eq)]
175pub struct Line<X = Comparand, V = ConstId> {
176 pub number: LineNumber,
177 pub fields: Vec<Field<X, V>>,
178}
179
180#[derive(Clone, Debug, PartialEq, Eq)]
181pub struct Field<X = Comparand, V = ConstId> {
182 pub item: usize,
183 pub column: usize,
185 pub content: FieldContent<X, V>,
186 pub group_indicate: bool,
187 pub blank_when_zero: bool,
189 pub rounded: bool,
190 pub pos: Pos,
191}
192
193#[derive(Clone, Debug, PartialEq, Eq)]
194pub enum FieldContent<X = Comparand, V = ConstId> {
195 Source(X),
196 Value(V),
197 Sum(usize),
198 Program,
200}
201
202#[derive(Clone, Debug, PartialEq, Eq)]
203pub struct Sum {
204 pub total: usize,
205 pub reset: Option<usize>,
207}
208
209#[derive(Clone, Debug, PartialEq, Eq)]
211pub enum Origin<X = Comparand, V = ConstId> {
212 Source(X),
213 Value(V),
214 Total(usize),
215}
216
217#[derive(Clone, Debug, PartialEq, Eq)]
218pub struct Subtotal<X = Comparand> {
219 pub sum: usize,
220 pub operand: X,
221 pub adding: Adding,
222}
223
224#[derive(Clone, Debug, PartialEq, Eq)]
225pub enum Adding {
226 EveryGenerate,
227 Upon(Vec<usize>),
229 Correlated(Vec<usize>),
231}
232
233pub fn span<X, V, U>(g: &Group<X, V, U>) -> i64 {
235 g.lines.iter().map(|l| if let LineNumber::Plus(k) = l.number { k as i64 } else { 0 }).sum()
236}
237
238pub fn generate_target<X, C, V, U>(reports: &[Report<X, C, V, U>], name: &str, qualifier: Option<&str>) -> Option<(usize, Option<usize>)> {
240 if qualifier.is_none()
241 && let Some(ri) = reports.iter().position(|r| r.name == name)
242 {
243 return Some((ri, None));
244 }
245 let mut found = reports
246 .iter()
247 .enumerate()
248 .filter(|(_, r)| qualifier.is_none_or(|q| r.name == q))
249 .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))));
250 let first = found.next()?;
251 found.next().is_none().then_some(first)
252}
253
254codec_enum!(ReportOp { Initiate(report) = 0, Generate { report, detail } = 1, Terminate(report) = 2, Suppress = 3 });
255codec_enum!(NextGroup { Line(line) = 0, Plus(lines) = 1, NextPage = 2 });
256codec_enum!(LineNumber { Line(line) = 0, Plus(lines) = 1, NextPage(line) = 2 });
257codec_struct!(Writer { reports, print_switch });
258codec_struct!(Report {
259 name, file, code, width, page, controls, groups, sums, subtotals, page_counter, line_counter, state, report_heading,
260 page_heading, page_footing, report_footing, control_headings, control_footings, first_detail_written,
261});
262codec_struct!(Page { limit, heading, first_detail, last_detail, footing });
263codec_struct!(Control { reference, saved, len });
264codec_enum!(GroupKind {
265 ReportHeading = 0,
266 PageHeading = 1,
267 ControlHeading = 2,
268 Detail = 3,
269 ControlFooting = 4,
270 PageFooting = 5,
271 ReportFooting = 6,
272});
273codec_struct!(Group { name, kind, level, next_group, lines, unprinted, cross, rolls, totals, indicate, declarative });
274codec_struct!(Line { number, fields });
275codec_struct!(Field { item, column, content, group_indicate, blank_when_zero, rounded, pos });
276codec_enum!(FieldContent { Source(expr) = 0, Value(value) = 1, Sum(sum) = 2, Program = 3 });
277codec_struct!(Sum { total, reset });
278codec_enum!(Origin { Source(expr) = 0, Value(value) = 1, Total(sum) = 2 });
279codec_struct!(Subtotal { sum, operand, adding });
280codec_enum!(Adding { EveryGenerate = 0, Upon(details) = 1, Correlated(details) = 2 });