From 560cb626a1a8f7d4bfca5d30f262cc90fb5d4608 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Fri, 10 Apr 2026 20:39:06 +0900 Subject: hst: remove enablement json adapter The go116 behaviour of built-in new function makes this cleaner. Signed-off-by: Ophestra --- internal/store/data.go | 13 ++++++++----- internal/store/header.go | 27 +++++++++++++++------------ internal/store/header_test.go | 2 +- internal/store/segment.go | 41 +++++++++++++++++++++++++++-------------- internal/store/segment_test.go | 2 +- 5 files changed, 52 insertions(+), 33 deletions(-) (limited to 'internal/store') diff --git a/internal/store/data.go b/internal/store/data.go index 00a23443..34a0f261 100644 --- a/internal/store/data.go +++ b/internal/store/data.go @@ -24,7 +24,7 @@ func entryEncode(w io.Writer, s *hst.State) error { } // entryDecodeHeader calls entryReadHeader, returning [hst.AppError] for a non-nil error. -func entryDecodeHeader(r io.Reader) (hst.Enablement, error) { +func entryDecodeHeader(r io.Reader) (hst.Enablements, error) { if et, err := entryReadHeader(r); err != nil { return 0, &hst.AppError{Step: "decode state header", Err: err} } else { @@ -32,11 +32,11 @@ func entryDecodeHeader(r io.Reader) (hst.Enablement, error) { } } -// entryDecode decodes [hst.State] from [io.Reader] and stores the result in the value pointed to by p. -// entryDecode validates the embedded [hst.Config] value. +// entryDecode decodes [hst.State] from [io.Reader] and stores the result in the +// value pointed to by p. entryDecode validates the embedded [hst.Config] value. // // A non-nil error returned by entryDecode is of type [hst.AppError]. -func entryDecode(r io.Reader, p *hst.State) (hst.Enablement, error) { +func entryDecode(r io.Reader, p *hst.State) (hst.Enablements, error) { if et, err := entryDecodeHeader(r); err != nil { return et, err } else if err = gob.NewDecoder(r).Decode(&p); err != nil { @@ -45,7 +45,10 @@ func entryDecode(r io.Reader, p *hst.State) (hst.Enablement, error) { return et, err } else if p.Enablements.Unwrap() != et { return et, &hst.AppError{Step: "validate state enablement", Err: os.ErrInvalid, - Msg: fmt.Sprintf("state entry %s has unexpected enablement byte %#x, %#x", p.ID.String(), byte(p.Enablements.Unwrap()), byte(et))} + Msg: fmt.Sprintf( + "state entry %s has unexpected enablement byte %#x, %#x", + p.ID.String(), byte(p.Enablements.Unwrap()), byte(et), + )} } else { return et, nil } diff --git a/internal/store/header.go b/internal/store/header.go index a6e756f9..5b5d73be 100644 --- a/internal/store/header.go +++ b/internal/store/header.go @@ -14,22 +14,25 @@ import ( const ( // entryHeaderMagic are magic bytes at the beginning of the state entry file. entryHeaderMagic = "\x00\xff\xca\xfe" - // entryHeaderRevision follows entryHeaderMagic and is incremented for revisions of the format. + // entryHeaderRevision follows entryHeaderMagic and is incremented for + // revisions of the format. entryHeaderRevision = "\x00\x00" - // entryHeaderSize is the fixed size of the header in bytes, including the enablement byte and its complement. + // entryHeaderSize is the fixed size of the header in bytes, including the + // enablement byte and its complement. entryHeaderSize = len(entryHeaderMagic+entryHeaderRevision) + 2 ) -// entryHeaderEncode encodes a state entry header for a [hst.Enablement] byte. -func entryHeaderEncode(et hst.Enablement) *[entryHeaderSize]byte { +// entryHeaderEncode encodes a state entry header for a [hst.Enablements] byte. +func entryHeaderEncode(et hst.Enablements) *[entryHeaderSize]byte { data := [entryHeaderSize]byte([]byte( - entryHeaderMagic + entryHeaderRevision + string([]hst.Enablement{et, ^et}), + entryHeaderMagic + entryHeaderRevision + string([]hst.Enablements{et, ^et}), )) return &data } -// entryHeaderDecode validates a state entry header and returns the [hst.Enablement] byte. -func entryHeaderDecode(data *[entryHeaderSize]byte) (hst.Enablement, error) { +// entryHeaderDecode validates a state entry header and returns the +// [hst.Enablements] byte. +func entryHeaderDecode(data *[entryHeaderSize]byte) (hst.Enablements, error) { if magic := data[:len(entryHeaderMagic)]; string(magic) != entryHeaderMagic { return 0, errors.New("invalid header " + hex.EncodeToString(magic)) } @@ -41,7 +44,7 @@ func entryHeaderDecode(data *[entryHeaderSize]byte) (hst.Enablement, error) { if et != ^data[len(entryHeaderMagic+entryHeaderRevision)+1] { return 0, errors.New("header enablement value is inconsistent") } - return hst.Enablement(et), nil + return hst.Enablements(et), nil } // EntrySizeError is returned for a file too small to hold a state entry header. @@ -68,8 +71,8 @@ func entryCheckFile(fi os.FileInfo) error { return nil } -// entryReadHeader reads [hst.Enablement] from an [io.Reader]. -func entryReadHeader(r io.Reader) (hst.Enablement, error) { +// entryReadHeader reads [hst.Enablements] from an [io.Reader]. +func entryReadHeader(r io.Reader) (hst.Enablements, error) { var data [entryHeaderSize]byte if n, err := r.Read(data[:]); err != nil { return 0, err @@ -79,8 +82,8 @@ func entryReadHeader(r io.Reader) (hst.Enablement, error) { return entryHeaderDecode(&data) } -// entryWriteHeader writes [hst.Enablement] header to an [io.Writer]. -func entryWriteHeader(w io.Writer, et hst.Enablement) error { +// entryWriteHeader writes [hst.Enablements] header to an [io.Writer]. +func entryWriteHeader(w io.Writer, et hst.Enablements) error { _, err := w.Write(entryHeaderEncode(et)[:]) return err } diff --git a/internal/store/header_test.go b/internal/store/header_test.go index 9da547f8..adebcac4 100644 --- a/internal/store/header_test.go +++ b/internal/store/header_test.go @@ -20,7 +20,7 @@ func TestEntryHeader(t *testing.T) { testCases := []struct { name string data [entryHeaderSize]byte - et hst.Enablement + et hst.Enablements err error }{ {"complement mismatch", [entryHeaderSize]byte{0x00, 0xff, 0xca, 0xfe, 0x00, 0x00, diff --git a/internal/store/segment.go b/internal/store/segment.go index c2a718ca..06849749 100644 --- a/internal/store/segment.go +++ b/internal/store/segment.go @@ -14,6 +14,7 @@ import ( ) // EntryHandle is a handle on a state entry retrieved from a [Handle]. +// // Must only be used while its parent [Handle.Lock] is held. type EntryHandle struct { // Error returned while decoding pathname. @@ -27,6 +28,7 @@ type EntryHandle struct { } // open opens the underlying state entry file. +// // A non-nil error returned by open is of type [hst.AppError]. func (eh *EntryHandle) open(flag int, perm os.FileMode) (*os.File, error) { if eh.DecodeErr != nil { @@ -41,6 +43,7 @@ func (eh *EntryHandle) open(flag int, perm os.FileMode) (*os.File, error) { } // Destroy removes the underlying state entry. +// // A non-nil error returned by Destroy is of type [hst.AppError]. func (eh *EntryHandle) Destroy() error { // destroy does not go through open @@ -55,8 +58,10 @@ func (eh *EntryHandle) Destroy() error { } // save encodes [hst.State] and writes it to the underlying file. +// // An error is returned if a file already exists with the same identifier. // save does not validate the embedded [hst.Config]. +// // A non-nil error returned by save is of type [hst.AppError]. func (eh *EntryHandle) save(state *hst.State) error { f, err := eh.open(os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) @@ -71,17 +76,19 @@ func (eh *EntryHandle) save(state *hst.State) error { return err } -// Load loads and validates the state entry header, and returns the [hst.Enablement] byte. -// for a non-nil v, the full state payload is decoded and stored in the value pointed to by v. -// Load validates the embedded [hst.Config] value. -// A non-nil error returned by Load is of type [hst.AppError]. -func (eh *EntryHandle) Load(v *hst.State) (hst.Enablement, error) { +// Load loads and validates the state entry header, and returns the +// [hst.Enablements] byte. For a non-nil v, the full state payload is decoded +// and stored in the value pointed to by v. +// +// Load validates the embedded [hst.Config] value. A non-nil error returned by +// Load is of type [hst.AppError]. +func (eh *EntryHandle) Load(v *hst.State) (hst.Enablements, error) { f, err := eh.open(os.O_RDONLY, 0) if err != nil { return 0, err } - var et hst.Enablement + var et hst.Enablements if v != nil { et, err = entryDecode(f, v) if err == nil && v.ID != eh.ID { @@ -99,6 +106,7 @@ func (eh *EntryHandle) Load(v *hst.State) (hst.Enablement, error) { } // Handle is a handle on a [Store] segment. +// // Initialised by [Store.Handle]. type Handle struct { // Identity of instances tracked by this segment. @@ -113,8 +121,9 @@ type Handle struct { mu sync.Mutex } -// Lock attempts to acquire a lock on [Handle]. -// If successful, Lock returns a non-nil unlock function. +// Lock attempts to acquire a lock on [Handle]. If successful, Lock returns a +// non-nil unlock function. +// // A non-nil error returned by Lock is of type [hst.AppError]. func (h *Handle) Lock() (unlock func(), err error) { if unlock, err = h.fileMu.Lock(); err != nil { @@ -123,20 +132,24 @@ func (h *Handle) Lock() (unlock func(), err error) { return } -// Save attempts to save [hst.State] as a segment entry, and returns its [EntryHandle]. -// Must be called while holding [Handle.Lock]. +// Save attempts to save [hst.State] as a segment entry, and returns its +// [EntryHandle]. Must be called while holding [Handle.Lock]. +// // An error is returned if an entry already exists with the same identifier. // Save does not validate the embedded [hst.Config]. +// // A non-nil error returned by Save is of type [hst.AppError]. func (h *Handle) Save(state *hst.State) (*EntryHandle, error) { eh := EntryHandle{nil, h.Path.Append(state.ID.String()), state.ID} return &eh, eh.save(state) } -// Entries returns an iterator over all [EntryHandle] held in this segment. -// Must be called while holding [Handle.Lock]. -// A non-nil error attached to a [EntryHandle] indicates a malformed identifier and is of type [hst.AppError]. -// A non-nil error returned by Entries is of type [hst.AppError]. +// Entries returns an iterator over all [EntryHandle] held in this segment. Must +// be called while holding [Handle.Lock]. +// +// A non-nil error attached to a [EntryHandle] indicates a malformed identifier +// and is of type [hst.AppError]. A non-nil error returned by Entries is of type +// [hst.AppError]. func (h *Handle) Entries() (iter.Seq[*EntryHandle], int, error) { // for error reporting const step = "read store segment entries" diff --git a/internal/store/segment_test.go b/internal/store/segment_test.go index 61b97c26..a244fcdc 100644 --- a/internal/store/segment_test.go +++ b/internal/store/segment_test.go @@ -21,7 +21,7 @@ import ( // Made available here for direct validation of state entry files. // //go:linkname entryDecode hakurei.app/internal/store.entryDecode -func entryDecode(r io.Reader, p *hst.State) (hst.Enablement, error) +func entryDecode(r io.Reader, p *hst.State) (hst.Enablements, error) // Made available here for direct access to known segment handles. // -- cgit v1.3.1