use super::{IntExpr, MovePlan, Operand, PlaceId, RangeId, SenderCheck, StorePlan, SymId};
use crate::files::Format;
use crate::vocab::{Closing, OpenMode, Pos};
use crate::module::ModuleError;
use crate::module::codec::{Decode, Encode, Reader, Writer};
use crate::{codec_enum, codec_struct};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FileDesc {
pub name: SymId,
pub assign: SymId,
pub organization: Organization,
pub access: Access,
pub optional: bool,
pub format: Format,
pub read_lengths: (u32, u32),
pub fixed: bool,
pub record_min: Option<u32>,
pub depending: Option<RecordDepending>,
pub status: Option<(PlaceId, MovePlan)>,
pub keys: Option<IndexKeys>,
pub relative: Option<RelativeKey>,
pub linage: Option<Linage>,
pub carriage: Option<Carriage>,
pub sort: bool,
pub error: Option<RangeId>,
pub assign_item: Option<AssignItem>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct AssignItem {
pub place: PlaceId,
pub select: Pos,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Organization {
Sequential,
LineSequential,
Indexed,
Relative,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Access {
Sequential,
Random,
Dynamic,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RecordDepending {
pub item: PlaceId,
pub lengths: (u32, u32),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RecordSpan {
pub offset: u32,
pub len: u32,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct IndexKeys {
pub prime: RecordSpan,
pub alternates: Vec<(RecordSpan, bool)>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RelativeKey {
pub place: PlaceId,
pub value: IntExpr,
pub store: StorePlan,
pub digits: Option<u32>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Linage {
pub lines: IntExpr,
pub footing: Option<IntExpr>,
pub top: Option<IntExpr>,
pub bottom: Option<IntExpr>,
pub counter: Option<(PlaceId, StorePlan)>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Carriage {
pub machine: bool,
pub reserved: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FileOp {
pub file: u16,
pub verb: FileVerb,
pub phrase: Option<Phrase>,
pub end_of_page: Option<Phrase>,
}
impl FileOp {
pub fn arms(&self) -> usize {
match (self.phrase, self.end_of_page) {
(None, None) => 0,
(_, None) => 3,
(_, Some(_)) => 5,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Phrase {
pub on: bool,
pub not_on: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FileVerb {
Open(OpenMode),
Close,
CloseWith(Closing),
Read { sequential: bool, previous: bool, into: Option<(PlaceId, MovePlan)>, key: u8 },
Write { record: PlaceId, from: Option<FromMove>, advancing: Option<Advance> },
Rewrite { record: PlaceId, from: Option<FromMove> },
Delete,
Start { rel: StartRel, key: StartKey },
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct FromMove {
pub from: Operand,
pub to: PlaceId,
pub plan: MovePlan,
pub check: SenderCheck,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Advance {
Lines { before: bool, count: IntExpr },
Page { before: bool },
Mnemonic { before: bool, space: Spacing },
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Spacing {
Lines(u64),
Channel(u8),
PageMode,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum StartRel {
Equal,
Greater,
NotLess,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum StartKey {
Prime,
Named { key: u8, span: RecordSpan },
Relative(IntExpr),
RelativeKey,
}
impl Encode for FileDesc {
fn encode(&self, w: &mut Writer) {
let FileDesc { name, assign, organization, access, optional, format, read_lengths, fixed, record_min, depending, status, keys, relative, linage, carriage, sort, error, assign_item: _ } = self;
name.encode(w);
assign.encode(w);
organization.encode(w);
access.encode(w);
optional.encode(w);
format.encode(w);
read_lengths.encode(w);
fixed.encode(w);
record_min.encode(w);
depending.encode(w);
status.encode(w);
keys.encode(w);
relative.encode(w);
linage.encode(w);
carriage.encode(w);
sort.encode(w);
error.encode(w);
}
}
impl Decode for FileDesc {
fn decode(r: &mut Reader<'_>) -> Result<Self, ModuleError> {
let at = r.position();
let file = FileDesc {
name: Decode::decode(r)?,
assign: Decode::decode(r)?,
organization: Decode::decode(r)?,
access: Decode::decode(r)?,
optional: Decode::decode(r)?,
format: Decode::decode(r)?,
read_lengths: Decode::decode(r)?,
fixed: Decode::decode(r)?,
record_min: Decode::decode(r)?,
depending: Decode::decode(r)?,
status: Decode::decode(r)?,
keys: Decode::decode(r)?,
relative: Decode::decode(r)?,
linage: Decode::decode(r)?,
carriage: Decode::decode(r)?,
sort: Decode::decode(r)?,
error: Decode::decode(r)?,
assign_item: None,
};
file_valid(&file).map_err(|reason| r.malformed(at, reason))?;
Ok(file)
}
}
codec_struct!(AssignItem { place, select });
codec_struct!(RecordDepending { item, lengths });
codec_enum!(Organization { Sequential = 0, LineSequential = 1, Indexed = 2, Relative = 3 });
codec_enum!(Access { Sequential = 0, Random = 1, Dynamic = 2 });
codec_struct!(RecordSpan { offset, len });
codec_struct!(IndexKeys { prime, alternates });
codec_struct!(RelativeKey { place, value, store, digits });
codec_struct!(Linage { lines, footing, top, bottom, counter });
codec_struct!(Carriage { machine, reserved });
codec_struct!(FileOp { file, verb, phrase, end_of_page });
codec_struct!(Phrase { on, not_on });
codec_enum!(FileVerb {
Open(mode) = 0,
Close = 1,
Read { sequential, previous, into, key } = 2,
Write { record, from, advancing } = 3,
Rewrite { record, from } = 4,
Delete = 5,
Start { rel, key } = 6,
CloseWith(closing) = 7,
});
codec_struct!(FromMove { from, to, plan, check });
codec_enum!(Advance { Lines { before, count } = 0, Page { before } = 1, Mnemonic { before, space } = 2 });
codec_enum!(Spacing { Lines(n) = 0, Channel(c) = 1, PageMode = 2 });
codec_enum!(StartRel { Equal = 0, Greater = 1, NotLess = 2 });
codec_enum!(StartKey { Prime = 0, Named { key, span } = 1, Relative(value) = 2, RelativeKey = 3 });
fn file_valid(file: &FileDesc) -> Result<(), String> {
if file.keys.is_some() == (file.organization == Organization::Indexed) {
Ok(())
} else {
Err("keys on a file that is not indexed, or an indexed file without them".into())
}
}