]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
resources: Optimize reading resource Content when it's already a string
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sat, 3 Feb 2024 10:40:08 +0000 (11:40 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sat, 3 Feb 2024 14:07:59 +0000 (15:07 +0100)
common/hugio/readers.go
resources/resource.go

index feb1b1412143bb923c4df49bc19f745557b8e6b8..9745d784152fcfd6abf0c16ca2fdf69d80ecab71 100644 (file)
@@ -37,32 +37,47 @@ type ReadSeekCloserProvider interface {
        ReadSeekCloser() (ReadSeekCloser, error)
 }
 
-// ReadSeekerNoOpCloser implements ReadSeekCloser by doing nothing in Close.
-// TODO(bep) rename this and similar to ReadSeekerNopCloser, naming used in stdlib, which kind of makes sense.
-type ReadSeekerNoOpCloser struct {
+// readSeekerNopCloser implements ReadSeekCloser by doing nothing in Close.
+type readSeekerNopCloser struct {
        ReadSeeker
 }
 
 // Close does nothing.
-func (r ReadSeekerNoOpCloser) Close() error {
+func (r readSeekerNopCloser) Close() error {
        return nil
 }
 
 // NewReadSeekerNoOpCloser creates a new ReadSeekerNoOpCloser with the given ReadSeeker.
-func NewReadSeekerNoOpCloser(r ReadSeeker) ReadSeekerNoOpCloser {
-       return ReadSeekerNoOpCloser{r}
+func NewReadSeekerNoOpCloser(r ReadSeeker) ReadSeekCloser {
+       return readSeekerNopCloser{r}
 }
 
 // NewReadSeekerNoOpCloserFromString uses strings.NewReader to create a new ReadSeekerNoOpCloser
 // from the given string.
-func NewReadSeekerNoOpCloserFromString(content string) ReadSeekerNoOpCloser {
-       return ReadSeekerNoOpCloser{strings.NewReader(content)}
+func NewReadSeekerNoOpCloserFromString(content string) ReadSeekCloser {
+       return strigReadSeeker{s: content, readSeekerNopCloser: readSeekerNopCloser{strings.NewReader(content)}}
+}
+
+var _ StringReader = (*strigReadSeeker)(nil)
+
+type strigReadSeeker struct {
+       s string
+       readSeekerNopCloser
+}
+
+func (s *strigReadSeeker) ReadString() string {
+       return s.s
+}
+
+// StringReader provides a way to read a string.
+type StringReader interface {
+       ReadString() string
 }
 
 // NewReadSeekerNoOpCloserFromString uses strings.NewReader to create a new ReadSeekerNoOpCloser
 // from the given bytes slice.
-func NewReadSeekerNoOpCloserFromBytes(content []byte) ReadSeekerNoOpCloser {
-       return ReadSeekerNoOpCloser{bytes.NewReader(content)}
+func NewReadSeekerNoOpCloserFromBytes(content []byte) readSeekerNopCloser {
+       return readSeekerNopCloser{bytes.NewReader(content)}
 }
 
 // NewReadSeekCloser creates a new ReadSeekCloser from the given ReadSeeker.
@@ -77,3 +92,15 @@ func NewOpenReadSeekCloser(r ReadSeekCloser) OpenReadSeekCloser {
 // OpenReadSeekCloser allows setting some other way (than reading from a filesystem)
 // to open or create a ReadSeekCloser.
 type OpenReadSeekCloser func() (ReadSeekCloser, error)
+
+// ReadString reads from the given reader and returns the content as a string.
+func ReadString(r io.Reader) (string, error) {
+       if sr, ok := r.(StringReader); ok {
+               return sr.ReadString(), nil
+       }
+       b, err := io.ReadAll(r)
+       if err != nil {
+               return "", err
+       }
+       return string(b), nil
+}
index 6bef1b2756e96f942bf300d4d95c93619be5c763..c11756bcaabdb16cac15852370b6b07f38076a4e 100644 (file)
@@ -418,12 +418,7 @@ func (l *genericResource) Content(context.Context) (any, error) {
        }
        defer r.Close()
 
-       var b []byte
-       b, err = io.ReadAll(r)
-       if err != nil {
-               return "", err
-       }
-       return string(b), nil
+       return hugio.ReadString(r)
 }
 
 func (r *genericResource) Err() resource.ResourceError {