vorteil/vorteil

View on GitHub
pkg/vio/writeseeker.go

Summary

Maintainability
A
35 mins
Test Coverage
F
0%
package vio

/**
 * SPDX-License-Identifier: Apache-2.0
 * Copyright 2020 vorteil.io Pty Ltd
 */

import (
    "errors"
    "io"
)

type zeroesReader struct {
}

func (rdr *zeroesReader) Read(p []byte) (n int, err error) {

    if len(p) == 0 {
        return
    }
    p[0] = 0
    for bp := 1; bp < len(p); bp *= 2 {
        copy(p[bp:], p[:bp])
    }

    return len(p), nil
}

var Zeroes = io.Reader(&zeroesReader{})

type writeSeeker struct {
    w io.Writer
    s io.Seeker
    k int64
}

func (ws *writeSeeker) Write(p []byte) (n int, err error) {
    n, err = ws.w.Write(p)
    if ws.s == nil {
        ws.k += int64(n)
    }
    return
}

func (ws *writeSeeker) Seek(offset int64, whence int) (int64, error) {
    switch whence {
    case io.SeekCurrent:
        if ws.s == nil {
            if offset < 0 {
                return 0, errors.New("streamio cannot go backwards")
            }
            k, err := io.CopyN(ws.w, Zeroes, offset)
            ws.k += k
            return ws.k, err
        } else {
            n, err := ws.s.Seek(offset, whence)
            return n - ws.k, err
        }
    case io.SeekStart:
        if ws.s == nil {
            whence = io.SeekCurrent
            offset = offset - ws.k
            return ws.Seek(offset, whence)
        } else {
            n, err := ws.s.Seek(offset+ws.k, whence)
            return n - ws.k, err
        }
    case io.SeekEnd:
        return 0, errors.New("streamio doesn't support io.SeekEnd")
    default:
        return 0, errors.New("invalid whence")
    }
}

func WriteSeeker(w io.Writer) (io.WriteSeeker, error) {

    ws := new(writeSeeker)
    ws.w = w

    if s, ok := w.(io.Seeker); ok {
        ws.s = s
        k, err := s.Seek(0, io.SeekCurrent)
        if err != nil {
            return nil, err
        }
        ws.k = k
    }

    return ws, nil

}