meta/signature/reader.go

Summary

Maintainability
A
40 mins
Test Coverage
F
5%
package signature

import (
    "bytes"
    "fmt"
    "io"

    "github.com/lugu/qiloop/type/basic"
)

// TypeReader reads from r the bytes representing the type
type TypeReader interface {
    Read(r io.Reader) ([]byte, error)
}

// constReader is a Reader which always read a constant size.
type constReader int

func (c constReader) Read(r io.Reader) ([]byte, error) {
    data := make([]byte, int(c))
    err := basic.ReadN(r, data, int(c))
    if err != nil {
        return nil, err
    }
    return data, nil
}

type stringReader struct{}

func (v stringReader) Read(r io.Reader) ([]byte, error) {
    str, err := basic.ReadString(r)
    var buf bytes.Buffer
    err = basic.WriteString(str, &buf)
    return buf.Bytes(), err
}

// UnknownReader is a TypeReader which returns an error.
type UnknownReader string

func (v UnknownReader) Read(r io.Reader) ([]byte, error) {
    return nil, fmt.Errorf("Unknown type '%v'", v)
}

type valueReader struct{}

func (v valueReader) Read(r io.Reader) ([]byte, error) {
    sig, err := basic.ReadString(r)
    if err != nil {
        return nil, fmt.Errorf("read signature: %s", err)
    }
    reader, err := MakeReader(sig)
    if err != nil {
        return nil, err
    }
    data, err := reader.Read(r)
    if err != nil {
        return nil, fmt.Errorf("read value: %s", err)
    }
    return append([]byte(sig), data...), err
}

type varReader struct {
    reader TypeReader
}

func (v varReader) Read(r io.Reader) ([]byte, error) {
    size, err := basic.ReadUint32(r)
    if err != nil {
        return nil, fmt.Errorf("read size: %s", err)
    }
    if int(size) < 0 {
        return nil, fmt.Errorf("invalid size: %d", size)
    }
    var buf bytes.Buffer
    err = basic.WriteUint32(size, &buf)
    if err != nil {
        return nil, fmt.Errorf("write size %d: %s",
            size, err)
    }
    for i := 0; i < int(size); i++ {
        data, err := v.reader.Read(r)
        if err != nil {
            return nil, fmt.Errorf("read %d/%d: %s",
                i+1, size, err)
        }
        err = basic.WriteN(&buf, data, len(data))
        if err != nil {
            return nil, fmt.Errorf("read %d/%d: %s",
                i, size, err)
        }
    }
    return buf.Bytes(), nil
}

type memberReader struct {
    name   string
    reader TypeReader
}

type tupleReader []memberReader

func (v tupleReader) Read(r io.Reader) ([]byte, error) {
    var buf bytes.Buffer
    for _, member := range v {
        name := member.name
        reader := member.reader
        data, err := reader.Read(r)
        if err != nil {
            return nil, fmt.Errorf("read %s: %s",
                name, err)
        }
        basic.WriteN(&buf, data, len(data))
        if err != nil {
            return nil, fmt.Errorf("write %s: %s",
                name, err)
        }
    }
    return buf.Bytes(), nil
}

// MakeReader parse the signature and returns its associated Reader.
func MakeReader(sig string) (TypeReader, error) {
    t, err := Parse(sig)
    if err != nil {
        return nil, err
    }
    return t.Reader(), nil
}