package pijul
import (
"fmt"
"io"
)
type EdgeFlags byte
const (
EdgeFlagsBlock EdgeFlags = 1
EdgeFlagsPseudo = 4
EdgeFlagsFolder = 16
EdgeFlagsParent = 32
EdgeFlagsDeleted = 128
)
func edgeFlags(data []byte) ([]byte, EdgeFlags, error) {
if len(data) < 1 {
return data, 0, io.ErrUnexpectedEOF
}
return data[1:], EdgeFlags(data[0]), nil
}
type ChangePosition uint64
func changePosition(data []byte) ([]byte, ChangePosition, error) {
return mapValue(uint64LE, func(v uint64) ChangePosition {
return ChangePosition(v)
})(data)
}
type Position struct {
Change OptionalHash
Pos ChangePosition
}
type OptionalHash struct {
Valid bool
Hash
}
func (h OptionalHash) String() string {
if !h.Valid {
return "None"
}
return fmt.Sprintf("Some(%s)", h.Hash.String())
}
func optionalHash(data []byte) ([]byte, OptionalHash, error) {
data, hp, err := option(hash)(data)
if err != nil {
return data, OptionalHash{}, err
}
if hp == nil {
return data, OptionalHash{}, nil
}
return data, OptionalHash{true, *hp}, nil
}
func position(data []byte) ([]byte, Position, error) {
var p Position
data, _, err := tuple(
assign(&p.Change, optionalHash),
assign(&p.Pos, changePosition),
)(data)
return data, p, err
}
type NewEdge struct {
Previous EdgeFlags
Flag EdgeFlags
From Position
To Vertex
IntroducedBy OptionalHash
}
func newEdge(data []byte) ([]byte, NewEdge, error) {
var ne NewEdge
data, _, err := tuple(
assign(&ne.Previous, edgeFlags),
assign(&ne.Flag, edgeFlags),
assign(&ne.From, position),
assign(&ne.To, vertex),
assign(&ne.IntroducedBy, optionalHash),
)(data)
return data, ne, err
}
type Vertex struct {
Change OptionalHash
Start ChangePosition
End ChangePosition
}
func vertex(data []byte) ([]byte, Vertex, error) {
var v Vertex
data, _, err := tuple(
assign(&v.Change, optionalHash),
assign(&v.Start, changePosition),
assign(&v.End, changePosition),
)(data)
return data, v, err
}
type Atom interface {
isAtom()
}
func atom(data []byte) ([]byte, Atom, error) {
data, tag, err := uint32LE(data)
if err != nil {
return data, nil, err
}
switch tag {
case 0:
return newVertex(data)
case 1:
return edgeMap(data)
default:
return data, nil, fmt.Errorf("unknown tag for Atom: %d", tag)
}
}
type NewVertex struct {
UpContext []Position
DownContext []Position
Flag EdgeFlags
Start ChangePosition
End ChangePosition
Inode Position
}
func (NewVertex) isAtom() {}
func newVertex(data []byte) ([]byte, NewVertex, error) {
var nv NewVertex
data, _, err := tuple(
assign(&nv.UpContext, vec(position)),
assign(&nv.DownContext, vec(position)),
assign(&nv.Flag, edgeFlags),
assign(&nv.Start, changePosition),
assign(&nv.End, changePosition),
assign(&nv.Inode, position),
)(data)
return data, nv, err
}
type EdgeMap struct {
Edges []NewEdge
Inode Position
}
func (EdgeMap) isAtom() {}
func edgeMap(data []byte) ([]byte, EdgeMap, error) {
var em EdgeMap
data, _, err := tuple(
assign(&em.Edges, vec(newEdge)),
assign(&em.Inode, position),
)(data)
return data, em, err
}
type Local struct {
Path string
Line uint64
}
func local(data []byte) ([]byte, Local, error) {
var l Local
data, _, err := tuple(
assign(&l.Path, toString(lengthData(uint64LE))),
assign(&l.Line, uint64LE),
)(data)
return data, l, err
}
type Hunk interface {
atoms() []Atom
}
func hunk(data []byte) ([]byte, Hunk, error) {
data, tag, err := uint32LE(data)
if err != nil {
return data, nil, err
}
switch tag {
case 0:
return fileMove(data)
case 1:
return fileDel(data)
case 2:
return fileUndel(data)
case 3:
return fileAdd(data)
case 4:
return solveNameConflict(data)
case 6:
return edit(data)
case 7:
return replacement(data)
case 8:
return solveOrderConflict(data)
case 10:
return resurrectZombies(data)
case 11:
return addRoot(data)
default:
return data, nil, fmt.Errorf("unknown tag for Hunk: %d", tag)
}
}
func hunkV4(data []byte) ([]byte, Hunk, error) {
data, tag, err := uint32LE(data)
if err != nil {
return data, nil, err
}
switch tag {
case 0:
return fileMove(data)
case 1:
return fileDelV4(data)
case 2:
return fileUndelV4(data)
case 3:
return fileAddV4(data)
case 4:
return solveNameConflict(data)
case 6:
return editV4(data)
case 7:
return replacementV4(data)
case 8:
return solveOrderConflict(data)
case 10:
return resurrectZombiesV4(data)
default:
return data, nil, fmt.Errorf("unknown tag for Hunk V4: %d", tag)
}
}
type FileAdd struct {
AddName Atom
AddInode Atom
Contents Atom
Path string
Encoding string
}
func (f FileAdd) atoms() []Atom {
if f.Contents == nil {
return []Atom{f.AddName, f.AddInode}
}
return []Atom{f.AddName, f.AddInode, f.Contents}
}
func fileAdd(data []byte) ([]byte, FileAdd, error) {
var f FileAdd
data, _, err := tuple(
assign(&f.AddName, atom),
assign(&f.AddInode, atom),
assign(&f.Contents, mapValue(option(atom), func(p *Atom) Atom {
if p == nil {
return nil
}
return *p
})),
assign(&f.Path, toString(lengthData(uint64LE))),
assign(&f.Encoding, mapValue(option(toString(lengthData(uint64LE))), func(p *string) string {
if p == nil {
return ""
}
return *p
})),
)(data)
return data, f, err
}
func fileAddV4(data []byte) ([]byte, FileAdd, error) {
var f FileAdd
f.Encoding = "UTF-8"
data, _, err := tuple(
assign(&f.AddName, atom),
assign(&f.AddInode, atom),
assign(&f.Contents, mapValue(option(atom), func(p *Atom) Atom {
if p == nil {
return nil
}
return *p
})),
assign(&f.Path, toString(lengthData(uint64LE))),
)(data)
return data, f, err
}
type AddRoot struct {
Name Atom
Inode Atom
}
func (a AddRoot) atoms() []Atom {
return []Atom{a.Name, a.Inode}
}
func addRoot(data []byte) ([]byte, AddRoot, error) {
var a AddRoot
data, _, err := tuple(
assign(&a.Name, atom),
assign(&a.Inode, atom),
)(data)
return data, a, err
}
type Edit struct {
Change Atom
Local Local
Encoding string
}
func (e Edit) atoms() []Atom {
return []Atom{e.Change}
}
func edit(data []byte) ([]byte, Edit, error) {
var e Edit
data, _, err := tuple(
assign(&e.Change, atom),
assign(&e.Local, local),
assign(&e.Encoding, mapValue(option(toString(lengthData(uint64LE))), func(p *string) string {
if p == nil {
return ""
}
return *p
})),
)(data)
return data, e, err
}
func editV4(data []byte) ([]byte, Edit, error) {
var e Edit
e.Encoding = "UTF-8"
data, _, err := tuple(
assign(&e.Change, atom),
assign(&e.Local, local),
)(data)
return data, e, err
}
type SolveOrderConflict struct {
Change Atom
Local Local
}
func (s SolveOrderConflict) atoms() []Atom {
return []Atom{s.Change}
}
func solveOrderConflict(data []byte) ([]byte, SolveOrderConflict, error) {
var s SolveOrderConflict
data, _, err := tuple(
assign(&s.Change, atom),
assign(&s.Local, local),
)(data)
return data, s, err
}
type Replacement struct {
Change Atom
Replacement Atom
Local Local
Encoding string
}
func (r Replacement) atoms() []Atom {
return []Atom{r.Change, r.Replacement}
}
func replacement(data []byte) ([]byte, Replacement, error) {
var r Replacement
data, _, err := tuple(
assign(&r.Change, atom),
assign(&r.Replacement, atom),
assign(&r.Local, local),
assign(&r.Encoding, mapValue(option(toString(lengthData(uint64LE))), func(p *string) string {
if p == nil {
return ""
}
return *p
})),
)(data)
return data, r, err
}
func replacementV4(data []byte) ([]byte, Replacement, error) {
var r Replacement
r.Encoding = "UTF-8"
data, _, err := tuple(
assign(&r.Change, atom),
assign(&r.Replacement, atom),
assign(&r.Local, local),
)(data)
return data, r, err
}
type FileDel struct {
Del Atom
Contents Atom
Path string
Encoding string
}
func (f FileDel) atoms() []Atom {
if f.Contents == nil {
return []Atom{f.Del}
}
return []Atom{f.Del, f.Contents}
}
func fileDel(data []byte) ([]byte, FileDel, error) {
var f FileDel
data, _, err := tuple(
assign(&f.Del, atom),
assign(&f.Contents, mapValue(option(atom), func(p *Atom) Atom {
if p == nil {
return nil
}
return *p
})),
assign(&f.Path, toString(lengthData(uint64LE))),
assign(&f.Encoding, mapValue(option(toString(lengthData(uint64LE))), func(p *string) string {
if p == nil {
return ""
}
return *p
})),
)(data)
return data, f, err
}
func fileDelV4(data []byte) ([]byte, FileDel, error) {
var f FileDel
f.Encoding = "UTF-8"
data, _, err := tuple(
assign(&f.Del, atom),
assign(&f.Contents, mapValue(option(atom), func(p *Atom) Atom {
if p == nil {
return nil
}
return *p
})),
assign(&f.Path, toString(lengthData(uint64LE))),
)(data)
return data, f, err
}
type ResurrectZombies struct {
Change Atom
Local Local
Encoding string
}
func (r ResurrectZombies) atoms() []Atom {
return []Atom{r.Change}
}
func resurrectZombies(data []byte) ([]byte, ResurrectZombies, error) {
var r ResurrectZombies
data, _, err := tuple(
assign(&r.Change, atom),
assign(&r.Local, local),
assign(&r.Encoding, optionalString),
)(data)
return data, r, err
}
func resurrectZombiesV4(data []byte) ([]byte, ResurrectZombies, error) {
var r ResurrectZombies
r.Encoding = "UTF-8"
data, _, err := tuple(
assign(&r.Change, atom),
assign(&r.Local, local),
)(data)
return data, r, err
}
type FileUndel struct {
Undel Atom
Contents Atom
Path string
Encoding string
}
func (f FileUndel) atoms() []Atom {
if f.Contents == nil {
return []Atom{f.Undel}
}
return []Atom{f.Undel, f.Contents}
}
func fileUndel(data []byte) ([]byte, FileUndel, error) {
var f FileUndel
data, _, err := tuple(
assign(&f.Undel, atom),
assign(&f.Contents, mapValue(option(atom), func(p *Atom) Atom {
if p == nil {
return nil
}
return *p
})),
assign(&f.Path, toString(lengthData(uint64LE))),
assign(&f.Encoding, optionalString),
)(data)
return data, f, err
}
func fileUndelV4(data []byte) ([]byte, FileUndel, error) {
var f FileUndel
f.Encoding = "UTF-8"
data, _, err := tuple(
assign(&f.Undel, atom),
assign(&f.Contents, mapValue(option(atom), func(p *Atom) Atom {
if p == nil {
return nil
}
return *p
})),
assign(&f.Path, toString(lengthData(uint64LE))),
)(data)
return data, f, err
}
type FileMove struct {
Del Atom
Add Atom
Path string
}
func (f FileMove) atoms() []Atom {
return []Atom{f.Del, f.Add}
}
func fileMove(data []byte) ([]byte, FileMove, error) {
var f FileMove
data, _, err := tuple(
assign(&f.Del, atom),
assign(&f.Add, atom),
assign(&f.Path, rustString),
)(data)
return data, f, err
}
type SolveNameConflict struct {
Name Atom
Path string
}
func (s SolveNameConflict) atoms() []Atom {
return []Atom{s.Name}
}
func solveNameConflict(data []byte) ([]byte, SolveNameConflict, error) {
var s SolveNameConflict
data, _, err := tuple(
assign(&s.Name, atom),
assign(&s.Path, rustString),
)(data)
return data, s, err
}