Documentation
¶
Overview ¶
Package study keeps a player's own notes and bookmarks on saved games.
A study lives beside its game rather than inside it. The game's record is canonical and carries digests that say what the game was, so nothing written here ever touches it; a study is this machine's annotation of one record, kept in a directory of its own with one file per saved game, named by the game's identifier. Exporting a game therefore exports the record alone, and deleting a saved game leaves its study file where it was, unattached but recoverable.
A study is tied to the record it was written against, not only to the game's identifier: it carries that record's digest. A note on entry 14 is about the position after the fourteenth entry of one particular record, so a study whose digest no longer matches the game's record is refused rather than moved onto a different position without anyone noticing.
Every successful save increments the study's revision, and a save names the revision it was made against. Two windows editing the same study cannot overwrite each other: the second to save finds that the revision has moved on and is refused, which leaves the first window's save on disk and the second window's text in its editor, both still there to be reconciled.
Index ¶
Constants ¶
const ( // Version is the study document format this build reads and writes. Version = 1 // MaxNoteBytes bounds one note, counted in UTF-8 bytes. MaxNoteBytes = 8 << 10 // MaxFileBytes bounds one study document on disk. Nothing this build // writes exceeds it, so anything that does was not written by twixtui. MaxFileBytes = 1 << 20 )
Variables ¶
var ( // ErrRecordChanged reports a stored study written against a different // record of the game. The study file is left as it is. ErrRecordChanged = errors.New("study belongs to a different record of this game") // ErrStale reports a save made against a revision the stored study has // since moved past. ErrStale = errors.New("study has been saved elsewhere since it was loaded") // ErrNewerVersion reports a study document written in a format newer than // this build knows. ErrNewerVersion = errors.New("study was written by a newer version of twixtui") // ErrCorrupt reports a study document that cannot be read as one, or, from // Set, one that can be read but can take no further save. ErrCorrupt = errors.New("study file is damaged") // ErrUnfinished reports a save for a game that has no result yet. ErrUnfinished = errors.New("game is not finished") // ErrInvalid reports a mark that cannot be saved. ErrInvalid = errors.New("invalid study mark") )
Functions ¶
This section is empty.
Types ¶
type Mark ¶
type Mark struct {
Entry int `json:"entry"`
Note string `json:"note,omitempty"`
Bookmark bool `json:"bookmark,omitempty"`
}
Mark is what a player keeps about one entry: a note, a bookmark, or both.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the collection of studies in one configuration directory.
func Open ¶
Open prepares the store of studies kept in configDir. The directory is created on the first save rather than here or on a load, so looking at a game nobody has taken notes on leaves nothing behind.
func (*Store) Load ¶
Load reads the study of the game t names. A game with no study yet has an empty one at revision 0.
A stored study written against a different record is refused with ErrRecordChanged, one from a newer format with ErrNewerVersion, and one that cannot be read as a study of this record with ErrCorrupt; each of them comes back with no study at all, so nothing from the refused file can be mistaken for this record's notes. Loading never writes, not even a lock file.
func (*Store) Set ¶
Set saves m in place of whatever mark its entry held, or removes that mark when m has neither a note nor a bookmark. baseRevision is the revision the caller loaded and edited.
The target and the mark are checked before anything is created, so a refused save of an unfinished game or of a bad mark leaves no trace. The stored study is then read again under the study's exclusive lock, which is held until the write is done: comparing revisions is only worth anything while nobody else can move them. A stored revision other than baseRevision means somebody else saved first; the save is refused with ErrStale and the current stored study is returned, so the caller can show what is there beside its own unsaved text. Otherwise the revision advances by one and the study is replaced atomically. A save that would make the study larger than MaxFileBytes is refused with ErrInvalid, since the file could not be loaded again.
A stored study already at revision math.MaxInt64 is refused with ErrCorrupt and left as it is. No run of saves gets a study that far, so something else wrote the number, and there is no next revision to give it: one more would wrap around to a negative revision that Load refuses, and a save reporting success would have made every note in the file unavailable. Refused, the file still loads with its notes. The check comes before the revisions are compared, because a stale refusal would invite the caller to try again against a study that can take no save at all.
type Study ¶
type Study struct {
Version int `json:"version"`
GameID string `json:"game_id"`
RecordDigest string `json:"record_digest"`
Revision int64 `json:"revision"`
// Marks is sorted by Entry, holds each entry at most once, and never holds
// a mark with neither a note nor a bookmark.
Marks []Mark `json:"entries"`
}
Study is the stored document for one saved game.
type Target ¶
type Target struct {
// GameID is the saved game's identifier. It becomes a file name, so it is
// checked with gamestore.ValidateID before it is used.
GameID string
// RecordDigest is the digest of the record the study is about.
RecordDigest string
// Entries is the number of transcript entries in the record. Marks may be
// placed on entries 0 through Entries, where 0 is the initial position.
Entries int
// Finished reports whether the record has a result. Only a finished game's
// study may be saved.
Finished bool
}
Target identifies the saved game a study belongs to. The caller derives it from the saved game's decoded, digest-checked record.