resources: Optimize reading resource Content when it's already a string

This commit is contained in:
Bjørn Erik Pedersen 2024-02-03 11:40:08 +01:00
parent 2873324898
commit e33a632551
2 changed files with 38 additions and 16 deletions

View file

@ -37,32 +37,47 @@ type ReadSeekCloserProvider interface {
ReadSeekCloser() (ReadSeekCloser, error) ReadSeekCloser() (ReadSeekCloser, error)
} }
// ReadSeekerNoOpCloser implements ReadSeekCloser by doing nothing in Close. // readSeekerNopCloser 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 readSeekerNopCloser struct {
type ReadSeekerNoOpCloser struct {
ReadSeeker ReadSeeker
} }
// Close does nothing. // Close does nothing.
func (r ReadSeekerNoOpCloser) Close() error { func (r readSeekerNopCloser) Close() error {
return nil return nil
} }
// NewReadSeekerNoOpCloser creates a new ReadSeekerNoOpCloser with the given ReadSeeker. // NewReadSeekerNoOpCloser creates a new ReadSeekerNoOpCloser with the given ReadSeeker.
func NewReadSeekerNoOpCloser(r ReadSeeker) ReadSeekerNoOpCloser { func NewReadSeekerNoOpCloser(r ReadSeeker) ReadSeekCloser {
return ReadSeekerNoOpCloser{r} return readSeekerNopCloser{r}
} }
// NewReadSeekerNoOpCloserFromString uses strings.NewReader to create a new ReadSeekerNoOpCloser // NewReadSeekerNoOpCloserFromString uses strings.NewReader to create a new ReadSeekerNoOpCloser
// from the given string. // from the given string.
func NewReadSeekerNoOpCloserFromString(content string) ReadSeekerNoOpCloser { func NewReadSeekerNoOpCloserFromString(content string) ReadSeekCloser {
return ReadSeekerNoOpCloser{strings.NewReader(content)} 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 // NewReadSeekerNoOpCloserFromString uses strings.NewReader to create a new ReadSeekerNoOpCloser
// from the given bytes slice. // from the given bytes slice.
func NewReadSeekerNoOpCloserFromBytes(content []byte) ReadSeekerNoOpCloser { func NewReadSeekerNoOpCloserFromBytes(content []byte) readSeekerNopCloser {
return ReadSeekerNoOpCloser{bytes.NewReader(content)} return readSeekerNopCloser{bytes.NewReader(content)}
} }
// NewReadSeekCloser creates a new ReadSeekCloser from the given ReadSeeker. // 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) // OpenReadSeekCloser allows setting some other way (than reading from a filesystem)
// to open or create a ReadSeekCloser. // to open or create a ReadSeekCloser.
type OpenReadSeekCloser func() (ReadSeekCloser, error) 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
}

View file

@ -418,12 +418,7 @@ func (l *genericResource) Content(context.Context) (any, error) {
} }
defer r.Close() defer r.Close()
var b []byte return hugio.ReadString(r)
b, err = io.ReadAll(r)
if err != nil {
return "", err
}
return string(b), nil
} }
func (r *genericResource) Err() resource.ResourceError { func (r *genericResource) Err() resource.ResourceError {