github.com/oweisse/u-root@v0.0.0-20181109060735-d005ad25fef1/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 ) 10 11 // LazyOpener is a lazy io.Reader. 12 // 13 // LazyOpener will use a given open function to derive an io.Reader when Read 14 // is first called on the LazyOpener. 15 type LazyOpener struct { 16 r io.Reader 17 err error 18 open func() (io.Reader, error) 19 } 20 21 // NewLazyOpener returns a lazy io.Reader based on `open`. 22 func NewLazyOpener(open func() (io.Reader, error)) io.ReadCloser { 23 return &LazyOpener{open: open} 24 } 25 26 // Read implements io.Reader.Read lazily. 27 // 28 // If called for the first time, the underlying reader will be obtained and 29 // then used for the first and subsequent calls to Read. 30 func (lr *LazyOpener) Read(p []byte) (int, error) { 31 if lr.r == nil && lr.err == nil { 32 lr.r, lr.err = lr.open() 33 } 34 if lr.err != nil { 35 return 0, lr.err 36 } 37 return lr.r.Read(p) 38 } 39 40 // Close implements io.Closer.Close. 41 func (lr *LazyOpener) Close() error { 42 if c, ok := lr.r.(io.Closer); ok { 43 return c.Close() 44 } 45 return nil 46 } 47 48 // ReadAtCloser is an io.ReaderAt and an io.Closer. 49 type ReadAtCloser interface { 50 io.ReaderAt 51 io.Closer 52 } 53 54 // LazyOpenerAt is a lazy io.ReaderAt. 55 // 56 // LazyOpenerAt will use a given open function to derive an io.ReaderAt when 57 // ReadAt is first called. 58 type LazyOpenerAt struct { 59 r io.ReaderAt 60 err error 61 open func() (io.ReaderAt, error) 62 } 63 64 // NewLazyOpenerAt returns a lazy io.ReaderAt based on `open`. 65 func NewLazyOpenerAt(open func() (io.ReaderAt, error)) ReadAtCloser { 66 return &LazyOpenerAt{open: open} 67 } 68 69 // ReadAt implements io.ReaderAt.ReadAt. 70 func (loa *LazyOpenerAt) ReadAt(p []byte, off int64) (int, error) { 71 if loa.r == nil && loa.err == nil { 72 loa.r, loa.err = loa.open() 73 } 74 if loa.err != nil { 75 return 0, loa.err 76 } 77 return loa.r.ReadAt(p, off) 78 } 79 80 // Close implements io.Closer.Close. 81 func (loa *LazyOpenerAt) Close() error { 82 if c, ok := loa.r.(io.Closer); ok { 83 return c.Close() 84 } 85 return nil 86 }