A library for working with Pijul repositories in Go
package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
)

type markedChange struct {
	mark  int
	state string
}

type Marks struct {
	marks   int
	changes []markedChange
}

func (m *Marks) Next() int {
	m.marks++
	return m.marks
}

func (m *Marks) MarkChanges(changes []change) {
	// Make a lookup table for existing marks, and make sure we don't
	// reuse them.
	stateToMark := make(map[string]int)
	for _, mc := range m.changes {
		stateToMark[mc.state] = mc.mark
		if mc.mark > m.marks {
			m.marks = mc.mark
		}
	}

	for i := range changes {
		if mark, ok := stateToMark[changes[i].State]; ok {
			changes[i].mark = mark
			changes[i].exported = true
		} else {
			changes[i].mark = m.Next()
			m.changes = append(m.changes, markedChange{
				mark:  changes[i].mark,
				state: changes[i].State,
			})
		}
	}
}

// Import loads a marks file analogous to those used by git fast-export's
// --import-marks and --export-marks switches.
func (m *Marks) Import(filename string) error {
	f, err := os.Open(filename)
	if err != nil {
		return err
	}
	defer f.Close()
	br := bufio.NewReader(f)

	for {
		var mc markedChange
		n, err := fmt.Fscanf(br, ":%d %s\n", &mc.mark, &mc.state)
		if err == io.ErrUnexpectedEOF && n == 0 {
			return nil
		}
		if err != nil {
			return err
		}
		m.changes = append(m.changes, mc)
	}
}

func (m *Marks) Export(filename string) error {
	f, err := os.Create(filename)
	if err != nil {
		return err
	}

	for _, c := range m.changes {
		fmt.Fprintf(f, ":%d %s\n", c.mark, c.state)
	}

	return f.Close()
}