github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/pkg/uio/lazy.go (about) 1 // Copyright 2018 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package uio 6 7 import ( 8 "io" 9 "os" 10 ) 11 12 // LazyOpener is a lazy io.Reader. 13 // 14 // LazyOpener will use a given open function to derive an io.Reader when Read 15 // is first called on the LazyOpener. 16 type LazyOpener struct { 17 r io.Reader 18 err error 19 open func() (io.Reader, error) 20 } 21 22 // NewLazyOpener returns a lazy io.Reader based on `open`. 23 func NewLazyOpener(open func() (io.Reader, error)) io.ReadCloser { 24 return &LazyOpener{open: open} 25 } 26 27 // Read implements io.Reader.Read lazily. 28 // 29 // If called for the first time, the underlying reader will be obtained and 30 // then used for the first and subsequent calls to Read. 31 func (lr *LazyOpener) Read(p []byte) (int, error) { 32 if lr.r == nil && lr.err == nil { 33 lr.r, lr.err = lr.open() 34 } 35 if lr.err != nil { 36 return 0, lr.err 37 } 38 return lr.r.Read(p) 39 } 40 41 // Close implements io.Closer.Close. 42 func (lr *LazyOpener) Close() error { 43 if c, ok := lr.r.(io.Closer); ok { 44 return c.Close() 45 } 46 return nil 47 } 48 49 // ReadAtCloser is an io.ReaderAt and an io.Closer. 50 type ReadAtCloser interface { 51 io.ReaderAt 52 io.Closer 53 } 54 55 // LazyOpenerAt is a lazy io.ReaderAt. 56 // 57 // LazyOpenerAt will use a given open function to derive an io.ReaderAt when 58 // ReadAt is first called. 59 type LazyOpenerAt struct { 60 r io.ReaderAt 61 err error 62 open func() (io.ReaderAt, error) 63 } 64 65 // NewLazyFile returns a lazy ReaderAt opened from path. 66 func NewLazyFile(path string) ReadAtCloser { 67 if len(path) == 0 { 68 return nil 69 } 70 return NewLazyOpenerAt(func() (io.ReaderAt, error) { 71 return os.Open(path) 72 }) 73 } 74 75 // NewLazyOpenerAt returns a lazy io.ReaderAt based on `open`. 76 func NewLazyOpenerAt(open func() (io.ReaderAt, error)) ReadAtCloser { 77 return &LazyOpenerAt{open: open} 78 } 79 80 // ReadAt implements io.ReaderAt.ReadAt. 81 func (loa *LazyOpenerAt) ReadAt(p []byte, off int64) (int, error) { 82 if loa.r == nil && loa.err == nil { 83 loa.r, loa.err = loa.open() 84 } 85 if loa.err != nil { 86 return 0, loa.err 87 } 88 return loa.r.ReadAt(p, off) 89 } 90 91 // Close implements io.Closer.Close. 92 func (loa *LazyOpenerAt) Close() error { 93 if c, ok := loa.r.(io.Closer); ok { 94 return c.Close() 95 } 96 return nil 97 }