github.com/puellanivis/breton@v0.2.16/lib/files/wrapper/reader.go (about) 1 package wrapper 2 3 import ( 4 "bytes" 5 "io" 6 "net/url" 7 "os" 8 "sync" 9 "time" 10 ) 11 12 // Reader implements files.Reader with an underlying byte slice. 13 type Reader struct { 14 mu sync.Mutex 15 16 fi os.FileInfo 17 r io.Reader 18 s io.Seeker 19 } 20 21 // NewReaderWithInfo returns a new Reader with the given FileInfo. 22 func NewReaderWithInfo(r io.Reader, info os.FileInfo) *Reader { 23 return &Reader{ 24 fi: info, 25 r: r, 26 } 27 } 28 29 // NewReaderFromBytes returns a new Reader with a NewInfo with uri, len(b) and time.Time specified. 30 func NewReaderFromBytes(b []byte, uri *url.URL, t time.Time) *Reader { 31 return NewReaderWithInfo(bytes.NewReader(b), NewInfo(uri, len(b), t)) 32 } 33 34 // Name implements files.File 35 func (r *Reader) Name() string { 36 return r.fi.Name() 37 } 38 39 // Stat implements files.File 40 func (r *Reader) Stat() (os.FileInfo, error) { 41 return r.fi, nil 42 } 43 44 // Read performs a thread-safe Read from the underlying Reader. 45 func (r *Reader) Read(b []byte) (int, error) { 46 r.mu.Lock() 47 defer r.mu.Unlock() 48 49 return r.r.Read(b) 50 } 51 52 // Seek performs a thread-safe Seek to the underlying Reader. 53 func (r *Reader) Seek(offset int64, whence int) (int64, error) { 54 r.mu.Lock() 55 defer r.mu.Unlock() 56 57 if r.s == nil { 58 switch s := r.r.(type) { 59 case io.Seeker: 60 r.s = s 61 default: 62 return 0, os.ErrInvalid 63 } 64 } 65 66 return r.s.Seek(offset, whence) 67 } 68 69 // Close recovers resources assigned in the Reader. 70 func (r *Reader) Close() error { 71 r.mu.Lock() 72 defer r.mu.Unlock() 73 74 var err error 75 76 switch c := r.r.(type) { 77 case nil: 78 err = os.ErrClosed 79 80 case io.Closer: 81 err = c.Close() 82 } 83 84 r.s = nil 85 r.r = nil 86 r.fi = nil 87 88 return err 89 }