bytes.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package blob
  2. import (
  3. "errors"
  4. "fmt"
  5. "sync"
  6. "sync/atomic"
  7. )
  8. var (
  9. // ensure Bytes conforms to these interfaces:
  10. _ interface {
  11. Blob
  12. ViewBlob
  13. SliceBlob
  14. SetBlob
  15. GrowBlob
  16. TruncateBlob
  17. } = (*Bytes)(nil)
  18. )
  19. // Bytes is a Blob that wraps a byte slice.
  20. type Bytes struct {
  21. mu *sync.Mutex // mutex can be shared when the byte slice is shared
  22. bytes []byte
  23. length int64
  24. }
  25. // NewBytes returns a Blob that wraps the given byte slice.
  26. // Mutations to this Blob are reflected in the original slice.
  27. func NewBytes(buf []byte) *Bytes {
  28. return &Bytes{
  29. bytes: buf,
  30. length: int64(len(buf)),
  31. mu: new(sync.Mutex),
  32. }
  33. }
  34. // NewBytesLength returns a new Bytes with the given length of zero-byte data.
  35. func NewBytesLength(length int) *Bytes {
  36. return NewBytes(make([]byte, length))
  37. }
  38. // Bytes implements Blob.
  39. func (b *Bytes) Bytes() []byte {
  40. // always return a copy of the bytes, to avoid concurrent modification
  41. newB, err := b.Slice(0, int64(b.Len()))
  42. if err != nil {
  43. panic(err)
  44. }
  45. return newB.(*Bytes).bytes
  46. }
  47. // Len implements Blob.
  48. func (b *Bytes) Len() int {
  49. return int(atomic.LoadInt64(&b.length))
  50. }
  51. // View implements Blob.
  52. func (b *Bytes) View(start, end int64) (Blob, error) {
  53. if start < 0 || start > int64(b.Len()) {
  54. return nil, fmt.Errorf("Start index out of bounds: %d", start)
  55. }
  56. if end < 0 || end > int64(b.Len()) {
  57. return nil, fmt.Errorf("End index out of bounds: %d", end)
  58. }
  59. b.mu.Lock()
  60. defer b.mu.Unlock()
  61. newB := NewBytes(b.bytes[start:end])
  62. newB.mu = b.mu
  63. return newB, nil
  64. }
  65. // Slice implements Blob.
  66. func (b *Bytes) Slice(start, end int64) (Blob, error) {
  67. if start < 0 || start > int64(b.Len()) {
  68. return nil, fmt.Errorf("Start index out of bounds: %d", start)
  69. }
  70. if end < 0 || end > int64(b.Len()) {
  71. return nil, fmt.Errorf("End index out of bounds: %d", end)
  72. }
  73. buf := make([]byte, end-start)
  74. b.mu.Lock()
  75. copy(buf, b.bytes)
  76. b.mu.Unlock()
  77. return NewBytes(buf), nil
  78. }
  79. // Set implements Blob.
  80. func (b *Bytes) Set(src Blob, destStart int64) (n int, err error) {
  81. if destStart < 0 {
  82. return 0, errors.New("negative offset")
  83. }
  84. if destStart >= int64(b.Len()) && destStart == 0 && src.Len() > 0 {
  85. return 0, fmt.Errorf("Offset out of bounds: %d", destStart)
  86. }
  87. b.mu.Lock()
  88. n = copy(b.bytes[destStart:], src.Bytes())
  89. b.mu.Unlock()
  90. return n, nil
  91. }
  92. // Grow implements Blob.
  93. func (b *Bytes) Grow(offset int64) error {
  94. b.mu.Lock()
  95. b.bytes = append(b.bytes, make([]byte, offset)...)
  96. atomic.StoreInt64(&b.length, int64(len(b.bytes)))
  97. b.mu.Unlock()
  98. return nil
  99. }
  100. // Truncate implements Blob.
  101. func (b *Bytes) Truncate(size int64) error {
  102. if int64(b.Len()) < size {
  103. return nil
  104. }
  105. b.mu.Lock()
  106. if int64(b.Len()) >= size {
  107. b.bytes = b.bytes[:size]
  108. atomic.StoreInt64(&b.length, int64(len(b.bytes)))
  109. }
  110. b.mu.Unlock()
  111. return nil
  112. }