We have a bit of a mess going on with the way PortBank Rows interact with the Record objects they use for I/O. I'm mainly looking at the input side of things right now, but any solution needs to also take output ops into account as well.
The problem is:
- PortBanks are attached to a Table, because there's a lot of fiddly field-creation that we don't want to have to recreate every time we load a new row, but we also need to make sure that the data in each PortRow doesn't persist when a new Row is loaded. (This created the alarming situation of user #1 being greeted as user #3 when viewing all of the user records -- something that most users wouldn't have permission to do, but which still suggests this could represent a huge security hole.)
- A Record should really be one and the same with the Storage PortRow; some of its operations really belong to the Logic or Display PortRow classes, where they relate to native calculations, display formatting, or user-input processing.
I think what I want is something like a mode-switch that tells everything within the Bank what the flow of data should be. When we're trying to read a Unit which has not been set, it should know whether or not to try to calculate a value by converting from its counterpart in one of the other PortRows. When we're trying to write out to Storage or Display, the PortRow being used for output should know whether to fill in missing Units by converting from one of the other two PortRows.
I think that should look like this:
- Each PortRow has a DataSource pointer which tells it where to convert from (NULL = self).
- When a new Row is read in to one of the I/O PortRows, the pointers for each PortRow are updated and existing data is cleared.
Example -- Storage reads a new row:
- Storage DataSource is set to NULL
- Native DataSource is set to Storage
- Display DataSource is set to Native
We also need to merge cStorageRow into the class-family somehow. Existing parentage:
- cStorageRow ← cPortIORow ← caPortRowInternalDirect ← caPortRowInternal ← caPortRow (root)
- caPortRow provides a few bits of connective tissue between itself and the PortBank, and then a bunch of Unit-access methods which are basically Array-access methods except each cell is a Unit instead of a value.
- caPortRowInternal defines an internal array and provides access methods for it, but does not implement the caPortRow access API
- caPortRowInternalDirect connects those access methods with the API
- cSingleRow ← F\cArrayLocalRW ← tArrayLocal ← taArrayReader
- taArrayReader provides a single abstract method for reading an array, and implements read-only methods using that
- taArrayWriter (just written) abstracts write methods
- tArrayLocal defines an internal array and provides R/W access methods for it
- tArrayHolder (not used here) provides a wrapper for a locally-stored ArrayLocal object, using the same API as ArrayLocal
There should be a way to replace caPortRowInternal with tArrayLocal, I think. For that matter, caPortRow is really just ArrayLocal plus PortBank-connector stuff plus "Unit"-named aliases for the ArrayLocal API.