...

Source file src/github.com/dsoprea/go-utility/v2/filesystem/seekable_buffer.go

Documentation: github.com/dsoprea/go-utility/v2/filesystem

     1  package rifs
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  
     7  	"github.com/dsoprea/go-logging"
     8  )
     9  
    10  // SeekableBuffer is a simple memory structure that satisfies
    11  // `io.ReadWriteSeeker`.
    12  type SeekableBuffer struct {
    13  	data     []byte
    14  	position int64
    15  }
    16  
    17  // NewSeekableBuffer is a factory that returns a `*SeekableBuffer`.
    18  func NewSeekableBuffer() *SeekableBuffer {
    19  	data := make([]byte, 0)
    20  
    21  	return &SeekableBuffer{
    22  		data: data,
    23  	}
    24  }
    25  
    26  // NewSeekableBufferWithBytes is a factory that returns a `*SeekableBuffer`.
    27  func NewSeekableBufferWithBytes(originalData []byte) *SeekableBuffer {
    28  	data := make([]byte, len(originalData))
    29  	copy(data, originalData)
    30  
    31  	return &SeekableBuffer{
    32  		data: data,
    33  	}
    34  }
    35  
    36  func len64(data []byte) int64 {
    37  	return int64(len(data))
    38  }
    39  
    40  // Bytes returns the underlying slice.
    41  func (sb *SeekableBuffer) Bytes() []byte {
    42  	return sb.data
    43  }
    44  
    45  // Len returns the number of bytes currently stored.
    46  func (sb *SeekableBuffer) Len() int {
    47  	return len(sb.data)
    48  }
    49  
    50  // Write does a standard write to the internal slice.
    51  func (sb *SeekableBuffer) Write(p []byte) (n int, err error) {
    52  	defer func() {
    53  		if state := recover(); state != nil {
    54  			err = log.Wrap(state.(error))
    55  		}
    56  	}()
    57  
    58  	// The current position we're already at is past the end of the data we
    59  	// actually have. Extend our buffer up to our current position.
    60  	if sb.position > len64(sb.data) {
    61  		extra := make([]byte, sb.position-len64(sb.data))
    62  		sb.data = append(sb.data, extra...)
    63  	}
    64  
    65  	positionFromEnd := len64(sb.data) - sb.position
    66  	tailCount := positionFromEnd - len64(p)
    67  
    68  	var tailBytes []byte
    69  	if tailCount > 0 {
    70  		tailBytes = sb.data[len64(sb.data)-tailCount:]
    71  		sb.data = append(sb.data[:sb.position], p...)
    72  	} else {
    73  		sb.data = append(sb.data[:sb.position], p...)
    74  	}
    75  
    76  	if tailBytes != nil {
    77  		sb.data = append(sb.data, tailBytes...)
    78  	}
    79  
    80  	dataSize := len64(p)
    81  	sb.position += dataSize
    82  
    83  	return int(dataSize), nil
    84  }
    85  
    86  // Read does a standard read against the internal slice.
    87  func (sb *SeekableBuffer) Read(p []byte) (n int, err error) {
    88  	defer func() {
    89  		if state := recover(); state != nil {
    90  			err = log.Wrap(state.(error))
    91  		}
    92  	}()
    93  
    94  	if sb.position >= len64(sb.data) {
    95  		return 0, io.EOF
    96  	}
    97  
    98  	n = copy(p, sb.data[sb.position:])
    99  	sb.position += int64(n)
   100  
   101  	return n, nil
   102  }
   103  
   104  // Truncate either chops or extends the internal buffer.
   105  func (sb *SeekableBuffer) Truncate(size int64) (err error) {
   106  	defer func() {
   107  		if state := recover(); state != nil {
   108  			err = log.Wrap(state.(error))
   109  		}
   110  	}()
   111  
   112  	sizeInt := int(size)
   113  	if sizeInt < len(sb.data)-1 {
   114  		sb.data = sb.data[:sizeInt]
   115  	} else {
   116  		new := make([]byte, sizeInt-len(sb.data))
   117  		sb.data = append(sb.data, new...)
   118  	}
   119  
   120  	return nil
   121  }
   122  
   123  // Seek does a standard seek on the internal slice.
   124  func (sb *SeekableBuffer) Seek(offset int64, whence int) (n int64, err error) {
   125  	defer func() {
   126  		if state := recover(); state != nil {
   127  			err = log.Wrap(state.(error))
   128  		}
   129  	}()
   130  
   131  	if whence == os.SEEK_SET {
   132  		sb.position = offset
   133  	} else if whence == os.SEEK_END {
   134  		sb.position = len64(sb.data) + offset
   135  	} else if whence == os.SEEK_CUR {
   136  		sb.position += offset
   137  	} else {
   138  		log.Panicf("seek whence is not valid: (%d)", whence)
   139  	}
   140  
   141  	if sb.position < 0 {
   142  		sb.position = 0
   143  	}
   144  
   145  	return sb.position, nil
   146  }
   147  

View as plain text