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 pub split: Vec<(u8, Vec<RecordSpan>)>,
96}
97
98#[derive(Clone, Debug, PartialEq, Eq)]
101pub struct RelativeKey {
102 pub place: PlaceId,
103 pub value: IntExpr,
104 pub store: StorePlan,
105 pub digits: Option<u32>,
106}
107
108#[derive(Clone, Debug, PartialEq, Eq)]
111pub struct Linage {
112 pub lines: IntExpr,
113 pub footing: Option<IntExpr>,
114 pub top: Option<IntExpr>,
115 pub bottom: Option<IntExpr>,
116 pub counter: Option<(PlaceId, StorePlan)>,
117}
118
119#[derive(Clone, Copy, Debug, PartialEq, Eq)]
122pub struct Carriage {
123 pub machine: bool,
124 pub reserved: bool,
125}
126
127#[derive(Clone, Debug, PartialEq, Eq)]
133pub struct FileOp {
134 pub file: u16,
135 pub verb: FileVerb,
136 pub phrase: Option<Phrase>,
137 pub end_of_page: Option<Phrase>,
138}
139
140impl FileOp {
141 pub fn arms(&self) -> usize {
143 match (self.phrase, self.end_of_page) {
144 (None, None) => 0,
145 (_, None) => 3,
146 (_, Some(_)) => 5,
147 }
148 }
149}
150
151#[derive(Clone, Copy, Debug, PartialEq, Eq)]
152pub struct Phrase {
153 pub on: bool,
154 pub not_on: bool,
155}
156
157#[derive(Clone, Debug, PartialEq, Eq)]
158pub enum FileVerb {
159 Open(OpenMode),
160 Close,
161 CloseWith(Closing),
162 Read { sequential: bool, previous: bool, into: Option<(PlaceId, MovePlan)>, key: u8 },
165 Write { record: PlaceId, from: Option<FromMove>, advancing: Option<Advance> },
167 Rewrite { record: PlaceId, from: Option<FromMove> },
168 Delete,
169 Start { rel: StartRel, key: StartKey },
170 DeleteFile,
172}
173
174#[derive(Clone, Copy, Debug, PartialEq, Eq)]
177pub struct FromMove {
178 pub from: Operand,
179 pub to: PlaceId,
180 pub plan: MovePlan,
181 pub check: SenderCheck,
182}
183
184#[derive(Clone, Debug, PartialEq, Eq)]
187pub enum Advance {
188 Lines { before: bool, count: IntExpr },
189 Page { before: bool },
190 Mnemonic { before: bool, space: Spacing },
192}
193
194#[derive(Clone, Copy, Debug, PartialEq, Eq)]
195pub enum Spacing {
196 Lines(u64),
198 Channel(u8),
199 PageMode,
201}
202
203#[derive(Clone, Copy, Debug, PartialEq, Eq)]
206pub enum StartRel {
207 Equal,
208 Greater,
209 NotLess,
210 Less,
211 NotGreater,
212}
213
214#[derive(Clone, Debug, PartialEq, Eq)]
215pub enum StartKey {
216 Prime,
218 Named { key: u8, span: RecordSpan },
220 Relative(IntExpr),
222 RelativeKey,
224}
225
226impl Encode for FileDesc {
229 fn encode(&self, w: &mut Writer) {
230 let FileDesc { name, assign, organization, access, optional, format, read_lengths, fixed, record_min, depending, status, keys, relative, linage, carriage, sort, error, assign_item: _ } = self;
231 name.encode(w);
232 assign.encode(w);
233 organization.encode(w);
234 access.encode(w);
235 optional.encode(w);
236 format.encode(w);
237 read_lengths.encode(w);
238 fixed.encode(w);
239 record_min.encode(w);
240 depending.encode(w);
241 status.encode(w);
242 keys.encode(w);
243 relative.encode(w);
244 linage.encode(w);
245 carriage.encode(w);
246 sort.encode(w);
247 error.encode(w);
248 }
249}
250
251impl Decode for FileDesc {
252 fn decode(r: &mut Reader<'_>) -> Result<Self, ModuleError> {
253 let at = r.position();
254 let file = FileDesc {
255 name: Decode::decode(r)?,
256 assign: Decode::decode(r)?,
257 organization: Decode::decode(r)?,
258 access: Decode::decode(r)?,
259 optional: Decode::decode(r)?,
260 format: Decode::decode(r)?,
261 read_lengths: Decode::decode(r)?,
262 fixed: Decode::decode(r)?,
263 record_min: Decode::decode(r)?,
264 depending: Decode::decode(r)?,
265 status: Decode::decode(r)?,
266 keys: Decode::decode(r)?,
267 relative: Decode::decode(r)?,
268 linage: Decode::decode(r)?,
269 carriage: Decode::decode(r)?,
270 sort: Decode::decode(r)?,
271 error: Decode::decode(r)?,
272 assign_item: None,
273 };
274 file_valid(&file).map_err(|reason| r.malformed(at, reason))?;
275 Ok(file)
276 }
277}
278codec_struct!(AssignItem { place, select });
279codec_struct!(RecordDepending { item, lengths });
280codec_enum!(Organization { Sequential = 0, LineSequential = 1, Indexed = 2, Relative = 3 });
281codec_enum!(Access { Sequential = 0, Random = 1, Dynamic = 2 });
282codec_struct!(RecordSpan { offset, len });
283codec_struct!(IndexKeys { prime, alternates } default { split } check crate::module::codec::unchecked);
284codec_struct!(RelativeKey { place, value, store, digits });
285codec_struct!(Linage { lines, footing, top, bottom, counter });
286codec_struct!(Carriage { machine, reserved });
287codec_struct!(FileOp { file, verb, phrase, end_of_page });
288codec_struct!(Phrase { on, not_on });
289codec_enum!(FileVerb {
290 Open(mode) = 0,
291 Close = 1,
292 Read { sequential, previous, into, key } = 2,
293 Write { record, from, advancing } = 3,
294 Rewrite { record, from } = 4,
295 Delete = 5,
296 Start { rel, key } = 6,
297 CloseWith(closing) = 7,
298 DeleteFile = 8,
299});
300codec_struct!(FromMove { from, to, plan, check });
301codec_enum!(Advance { Lines { before, count } = 0, Page { before } = 1, Mnemonic { before, space } = 2 });
302codec_enum!(Spacing { Lines(n) = 0, Channel(c) = 1, PageMode = 2 });
303codec_enum!(StartRel { Equal = 0, Greater = 1, NotLess = 2, Less = 3, NotGreater = 4 });
304codec_enum!(StartKey { Prime = 0, Named { key, span } = 1, Relative(value) = 2, RelativeKey = 3 });
305
306fn file_valid(file: &FileDesc) -> Result<(), String> {
308 if file.keys.is_some() == (file.organization == Organization::Indexed) {
309 Ok(())
310 } else {
311 Err("keys on a file that is not indexed, or an indexed file without them".into())
312 }
313}