1use super::{IntExpr, MovePlan, Operand, PlaceId, RangeId, SenderCheck, StorePlan, SymId};
6use crate::files::Format;
7use crate::vocab::{Closing, OpenMode, Pos};
8use crate::module::ModuleError;
9use crate::module::codec::{Decode, Encode, Reader, Writer};
10use crate::{codec_enum, codec_struct};
11
12#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct FileDesc {
16 pub name: SymId,
17 pub assign: SymId,
19 pub organization: Organization,
20 pub access: Access,
21 pub optional: bool,
22 pub format: Format,
23 pub read_lengths: (u32, u32),
27 pub fixed: bool,
29 pub record_min: Option<u32>,
31 pub depending: Option<RecordDepending>,
32 pub status: Option<(PlaceId, MovePlan)>,
33 pub keys: Option<IndexKeys>,
35 pub relative: Option<RelativeKey>,
36 pub linage: Option<Linage>,
37 pub carriage: Option<Carriage>,
39 pub sort: bool,
41 pub error: Option<RangeId>,
43 pub assign_item: Option<AssignItem>,
46}
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq)]
50pub struct AssignItem {
51 pub place: PlaceId,
52 pub select: Pos,
53}
54
55#[derive(Clone, Copy, Debug, PartialEq, Eq)]
56pub enum Organization {
57 Sequential,
58 LineSequential,
59 Indexed,
60 Relative,
61}
62
63#[derive(Clone, Copy, Debug, PartialEq, Eq)]
64pub enum Access {
65 Sequential,
66 Random,
67 Dynamic,
68}
69
70#[derive(Clone, Copy, Debug, PartialEq, Eq)]
74pub struct RecordDepending {
75 pub item: PlaceId,
76 pub lengths: (u32, u32),
77}
78
79#[derive(Clone, Copy, Debug, PartialEq, Eq)]
81pub struct RecordSpan {
82 pub offset: u32,
83 pub len: u32,
84}
85
86#[derive(Clone, Debug, PartialEq, Eq)]
89pub struct IndexKeys {
90 pub prime: RecordSpan,
91 pub alternates: Vec<(RecordSpan, bool)>,
92}
93
94#[derive(Clone, Debug, PartialEq, Eq)]
97pub struct RelativeKey {
98 pub place: PlaceId,
99 pub value: IntExpr,
100 pub store: StorePlan,
101 pub digits: Option<u32>,
102}
103
104#[derive(Clone, Debug, PartialEq, Eq)]
107pub struct Linage {
108 pub lines: IntExpr,
109 pub footing: Option<IntExpr>,
110 pub top: Option<IntExpr>,
111 pub bottom: Option<IntExpr>,
112 pub counter: Option<(PlaceId, StorePlan)>,
113}
114
115#[derive(Clone, Copy, Debug, PartialEq, Eq)]
118pub struct Carriage {
119 pub machine: bool,
120 pub reserved: bool,
121}
122
123#[derive(Clone, Debug, PartialEq, Eq)]
129pub struct FileOp {
130 pub file: u16,
131 pub verb: FileVerb,
132 pub phrase: Option<Phrase>,
133 pub end_of_page: Option<Phrase>,
134}
135
136impl FileOp {
137 pub fn arms(&self) -> usize {
139 match (self.phrase, self.end_of_page) {
140 (None, None) => 0,
141 (_, None) => 3,
142 (_, Some(_)) => 5,
143 }
144 }
145}
146
147#[derive(Clone, Copy, Debug, PartialEq, Eq)]
148pub struct Phrase {
149 pub on: bool,
150 pub not_on: bool,
151}
152
153#[derive(Clone, Debug, PartialEq, Eq)]
154pub enum FileVerb {
155 Open(OpenMode),
156 Close,
157 CloseWith(Closing),
158 Read { sequential: bool, previous: bool, into: Option<(PlaceId, MovePlan)>, key: u8 },
161 Write { record: PlaceId, from: Option<FromMove>, advancing: Option<Advance> },
163 Rewrite { record: PlaceId, from: Option<FromMove> },
164 Delete,
165 Start { rel: StartRel, key: StartKey },
166}
167
168#[derive(Clone, Copy, Debug, PartialEq, Eq)]
171pub struct FromMove {
172 pub from: Operand,
173 pub to: PlaceId,
174 pub plan: MovePlan,
175 pub check: SenderCheck,
176}
177
178#[derive(Clone, Debug, PartialEq, Eq)]
181pub enum Advance {
182 Lines { before: bool, count: IntExpr },
183 Page { before: bool },
184 Mnemonic { before: bool, space: Spacing },
186}
187
188#[derive(Clone, Copy, Debug, PartialEq, Eq)]
189pub enum Spacing {
190 Lines(u64),
192 Channel(u8),
193 PageMode,
195}
196
197#[derive(Clone, Copy, Debug, PartialEq, Eq)]
199pub enum StartRel {
200 Equal,
201 Greater,
202 NotLess,
203}
204
205#[derive(Clone, Debug, PartialEq, Eq)]
206pub enum StartKey {
207 Prime,
209 Named { key: u8, span: RecordSpan },
211 Relative(IntExpr),
213 RelativeKey,
215}
216
217impl Encode for FileDesc {
220 fn encode(&self, w: &mut Writer) {
221 let FileDesc { name, assign, organization, access, optional, format, read_lengths, fixed, record_min, depending, status, keys, relative, linage, carriage, sort, error, assign_item: _ } = self;
222 name.encode(w);
223 assign.encode(w);
224 organization.encode(w);
225 access.encode(w);
226 optional.encode(w);
227 format.encode(w);
228 read_lengths.encode(w);
229 fixed.encode(w);
230 record_min.encode(w);
231 depending.encode(w);
232 status.encode(w);
233 keys.encode(w);
234 relative.encode(w);
235 linage.encode(w);
236 carriage.encode(w);
237 sort.encode(w);
238 error.encode(w);
239 }
240}
241
242impl Decode for FileDesc {
243 fn decode(r: &mut Reader<'_>) -> Result<Self, ModuleError> {
244 let at = r.position();
245 let file = FileDesc {
246 name: Decode::decode(r)?,
247 assign: Decode::decode(r)?,
248 organization: Decode::decode(r)?,
249 access: Decode::decode(r)?,
250 optional: Decode::decode(r)?,
251 format: Decode::decode(r)?,
252 read_lengths: Decode::decode(r)?,
253 fixed: Decode::decode(r)?,
254 record_min: Decode::decode(r)?,
255 depending: Decode::decode(r)?,
256 status: Decode::decode(r)?,
257 keys: Decode::decode(r)?,
258 relative: Decode::decode(r)?,
259 linage: Decode::decode(r)?,
260 carriage: Decode::decode(r)?,
261 sort: Decode::decode(r)?,
262 error: Decode::decode(r)?,
263 assign_item: None,
264 };
265 file_valid(&file).map_err(|reason| r.malformed(at, reason))?;
266 Ok(file)
267 }
268}
269codec_struct!(AssignItem { place, select });
270codec_struct!(RecordDepending { item, lengths });
271codec_enum!(Organization { Sequential = 0, LineSequential = 1, Indexed = 2, Relative = 3 });
272codec_enum!(Access { Sequential = 0, Random = 1, Dynamic = 2 });
273codec_struct!(RecordSpan { offset, len });
274codec_struct!(IndexKeys { prime, alternates });
275codec_struct!(RelativeKey { place, value, store, digits });
276codec_struct!(Linage { lines, footing, top, bottom, counter });
277codec_struct!(Carriage { machine, reserved });
278codec_struct!(FileOp { file, verb, phrase, end_of_page });
279codec_struct!(Phrase { on, not_on });
280codec_enum!(FileVerb {
281 Open(mode) = 0,
282 Close = 1,
283 Read { sequential, previous, into, key } = 2,
284 Write { record, from, advancing } = 3,
285 Rewrite { record, from } = 4,
286 Delete = 5,
287 Start { rel, key } = 6,
288 CloseWith(closing) = 7,
289});
290codec_struct!(FromMove { from, to, plan, check });
291codec_enum!(Advance { Lines { before, count } = 0, Page { before } = 1, Mnemonic { before, space } = 2 });
292codec_enum!(Spacing { Lines(n) = 0, Channel(c) = 1, PageMode = 2 });
293codec_enum!(StartRel { Equal = 0, Greater = 1, NotLess = 2 });
294codec_enum!(StartKey { Prime = 0, Named { key, span } = 1, Relative(value) = 2, RelativeKey = 3 });
295
296fn file_valid(file: &FileDesc) -> Result<(), String> {
298 if file.keys.is_some() == (file.organization == Organization::Indexed) {
299 Ok(())
300 } else {
301 Err("keys on a file that is not indexed, or an indexed file without them".into())
302 }
303}