Task: Bitwise IO

C: #include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

typedef uint8_t byte;
typedef struct {
    FILE *fp;
    uint32_t accu;
    int bits;
} bit_io_t, *bit_filter;

bit_filter b_attach(FILE *f)
{
    bit_filter b = malloc(sizeof(bit_io_t));
    b->bits = b->accu = 0;
    b->fp = f;
    return b;
}

void b_write(byte *buf, size_t n_bits, size_t shift, bit_filter bf)
{
    uint32_t accu = bf->accu;
    int bits = bf->bits;

    buf += shift / 8;
    shift %= 8;

    while (n_bits || bits >= 8) {
        while (bits >= 8) {
            bits -= 8;
            fputc(accu >> bits, bf->fp);
            accu &= (1 << bits) - 1;
        }
        while (bits < 8 && n_bits) {
            accu = (accu << 1) | (((128 >> shift) & *buf) >> (7 - shift));
            --n_bits;
            bits++;
            if (++shift == 8) {
                shift = 0;
                buf++;
            }
        }
    }
    bf->accu = accu;
    bf->bits = bits;
}

size_t b_read(byte *buf, size_t n_bits, size_t shift, bit_filter bf)
{
    uint32_t accu = bf->accu;
    int bits = bf->bits;
    int mask, i = 0;

    buf += shift / 8;
    shift %= 8;

    while (n_bits) {
        while (bits && n_bits) {
            mask = 128 >> shift;
            if (accu & (1 << (bits - 1))) *buf |= mask;
            else *buf &= ~mask;

            n_bits--;
            bits--;

            if (++shift >= 8) {
                shift = 0;
                buf++;
            }
        }
        if (!n_bits) break;
        accu = (accu << 8) | fgetc(bf->fp);
        bits += 8;
    }
    bf->accu = accu;
    bf->bits = bits;

    return i;
}

void b_detach(bit_filter bf)
{
    if (bf->bits) {
        bf->accu <<= 8 - bf->bits;
        fputc(bf->accu, bf->fp);
    }
    free(bf);
}

int main()
{
    unsigned char s[] = "abcdefghijk";
    unsigned char s2[11] = {0};
    int i;

    FILE *f = fopen("test.bin", "wb");
    bit_filter b = b_attach(f);
    
    for (i = 0; i < 10; i++) b_write(s + i, 7, 1, b);
    b_detach(b);
    fclose(f);

    
    f = fopen("test.bin", "rb");
    b = b_attach(f);
    for (i = 0; i < 10; i++) b_read(s2 + i, 7, 1, b);
    b_detach(b);
    fclose(f);

    printf("%10s\n", s2); 

    return 0;
}




Go: 
package bit

import (
    "bufio"
    "errors"
    "io"
)


type Order int

const (
    
    LSB Order = iota
    
    MSB
)



type writer interface {
    io.ByteWriter
    Flush() error
}


type Writer struct {
    w     writer
    order Order
    write func(uint32, uint) error 
    bits  uint32
    nBits uint
    err   error
}


func (w *Writer) writeLSB(c uint32, width uint) error {
    w.bits |= c << w.nBits
    w.nBits += width
    for w.nBits >= 8 {
        if err := w.w.WriteByte(uint8(w.bits)); err != nil {
            return err
        }
        w.bits >>= 8
        w.nBits -= 8
    }
    return nil
}


func (w *Writer) writeMSB(c uint32, width uint) error {
    w.bits |= c << (32 - width - w.nBits)
    w.nBits += width
    for w.nBits >= 8 {
        if err := w.w.WriteByte(uint8(w.bits >> 24)); err != nil {
            return err
        }
        w.bits <<= 8
        w.nBits -= 8
    }
    return nil
}




func (w *Writer) WriteBits(c uint16, width uint) error {
    if w.err == nil {
        w.err = w.write(uint32(c), width)
    }
    return w.err
}

var errClosed = errors.New("bit reader/writer is closed")



func (w *Writer) Close() error {
    if w.err != nil {
        if w.err == errClosed {
            return nil
        }
        return w.err
    }
    
    if w.nBits > 0 {
        if w.order == MSB {
            w.bits >>= 24
        }
        if w.err = w.w.WriteByte(uint8(w.bits)); w.err != nil {
            return w.err
        }
    }
    w.err = w.w.Flush()
    if w.err != nil {
        return w.err
    }

    
    w.err = errClosed
    return nil
}


func NewWriter(w io.Writer, order Order) *Writer {
    bw := &Writer{order: order}
    switch order {
    case LSB:
        bw.write = bw.writeLSB
    case MSB:
        bw.write = bw.writeMSB
    default:
        bw.err = errors.New("bit writer: unknown order")
        return bw
    }
    if byteWriter, ok := w.(writer); ok {
        bw.w = byteWriter
    } else {
        bw.w = bufio.NewWriter(w)
    }
    return bw
}




type Reader struct {
    r     io.ByteReader
    bits  uint32
    nBits uint
    read  func(width uint) (uint16, error) 
    err   error
}

func (r *Reader) readLSB(width uint) (uint16, error) {
    for r.nBits < width {
        x, err := r.r.ReadByte()
        if err != nil {
            return 0, err
        }
        r.bits |= uint32(x) << r.nBits
        r.nBits += 8
    }
    bits := uint16(r.bits & (1<<width - 1))
    r.bits >>= width
    r.nBits -= width
    return bits, nil
}

func (r *Reader) readMSB(width uint) (uint16, error) {
    for r.nBits < width {
        x, err := r.r.ReadByte()
        if err != nil {
            return 0, err
        }
        r.bits |= uint32(x) << (24 - r.nBits)
        r.nBits += 8
    }
    bits := uint16(r.bits >> (32 - width))
    r.bits <<= width
    r.nBits -= width
    return bits, nil
}


func (r *Reader) ReadBits(width uint) (uint16, error) {
    var bits uint16
    if r.err == nil {
        bits, r.err = r.read(width)
    }
    return bits, r.err
}



func (r *Reader) Close() error {
    if r.err != nil && r.err != errClosed {
        return r.err
    }
    r.err = errClosed
    return nil
}


func NewReader(r io.Reader, order Order) *Reader {
    br := new(Reader)
    switch order {
    case LSB:
        br.read = br.readLSB
    case MSB:
        br.read = br.readMSB
    default:
        br.err = errors.New("bit writer: unknown order")
        return br
    }
    if byteReader, ok := r.(io.ByteReader); ok {
        br.r = byteReader
    } else {
        br.r = bufio.NewReader(r)
    }
    return br
}