<commit_before>package main

import (
	"sort"
	"strings"
)

// Sequence is an interface for single character sequences stored as a string
// and multi-character sequences stored as a slice.
type Sequence interface {
	ID() string
	Title() string
	Sequence() string
	Char(int) string
	SetSequence(string)
	ToUpper()
	ToLower()
	UngappedCoords(string) []int
	UngappedPositionSlice(string) []int
}

// CharSequence struct for storing single-character biological sequences such
// as nucleotides and single-letter amino acids. However, any sequence that
// whose element can be represented as a single string character can be stored
// in CharSequence.
type CharSequence struct {
	id    string
	title string
	seq   string
}

// ID returns the id field of CharSequence.
func (s *CharSequence) ID() string {
	return s.id
}

// Title returns the title field of CharSequence.
func (s *CharSequence) Title() string {
	return s.title
}

// Sequence returns the seq field of CharSequence.
func (s *CharSequence) Sequence() string {
	return s.seq
}

// Char returns a single character from the seq field of CharSequence.
func (s *CharSequence) Char(i int) string {
	return string(s.seq[i])
}

// SetSequence assigns a string to the seq field of CharSequence.
func (s *CharSequence) SetSequence(seq string) {
	s.seq = seq
}

// UngappedCoords returns the positions in the sequence where the character
// does not match the gap character.
func (s *CharSequence) UngappedCoords(gapChar string) (colCoords []int) {
	set := make(map[int]struct{})
	for j := 0; j < len(s.seq); j++ {
		if string(s.seq[j]) != gapChar {
			set[j] = struct{}{}
		}
	}
	for key := range set {
		colCoords = append(colCoords, key)
	}
	sort.Ints(colCoords)
	return
}

// UngappedPositionSlice returns a slice that counts only over characters
// that does not match the gap character in the sequence.
// If a character matches the gap character, -1 is inserted instead of the
// ungapped count.
func (s *CharSequence) UngappedPositionSlice(gapChar string) (arr []int) {
	cnt := 0
	for j := 0; j < len(s.seq); j++ {
		if string(s.seq[j]) != gapChar {
			arr = append(arr, cnt)
			cnt++
		} else {
			arr = append(arr, -1)
		}
	}
	return
}

// ToUpper changes the case of the sequence to all uppercase letters.
func (s *CharSequence) ToUpper() {
	s.seq = strings.ToUpper(s.seq)
}

// ToLower changes the case of the sequence to all lowercase letters.
func (s *CharSequence) ToLower() {
	s.seq = strings.ToLower(s.seq)
}

// CodonSequence is a struct for specifically designed for triplet nucleotide
// codon sequences. It embeds the CharSequence struct which also gives it
// id, title and seq fields. Additionally, CodonSequence has a prot field which
// stores a string and a codon string field which stores a slice of strings.
// The seq, prot and codons fields follow a positional correspondence.
// The first item in the codons slice translates to the first character
// in the prot string. The first item in the codons slice is equal to
// the first three characters of the seq string. This codon-seq correspondence
// should be consistent across the entire sequence.
type CodonSequence struct {
	CharSequence
	prot   string
	codons []string
}

// NewCodonSequence is a constructor that creates a new CodonSequence where
// prot and codons field values are automatically computed from the provided
// nucleotide sequence.
func NewCodonSequence(id, title, seq string) *CodonSequence {
	if len(seq)%3 == 0 {
		panic("seq length not divisible by 3")
	}
	s := new(CodonSequence)
	s.id = id
	s.title = title
	s.SetSequence(seq)
	return s
}

// ID returns the id field of CodonSequence.
func (s *CodonSequence) ID() string {
	return s.id
}

// Title returns the title field of CodonSequence.
func (s *CodonSequence) Title() string {
	return s.title
}

// Sequence returns the seq field of CodonSequence. The seq field contains
// a nucleotide sequence stored as a string.
func (s *CodonSequence) Sequence() string {
	return s.seq
}

// Codons returns the codon field of CodonSequence. The codon field
// contains a nucleotide sequence delimited by codon. This is stored
// as a slice of 3-character strings.
func (s *CodonSequence) Codons() []string {
	return s.codons
}

// Prot returns the prot field of CodonSequence. The prot field
// contains the translated amino acid sequence based on the seq
// field using the standard genetic code. The amino acid sequence
// is encoded as single-character amino acids and stored as a
// string.
func (s *CodonSequence) Prot() string {
	return s.prot
}

// Char returns a single nucleotide from the seq field of CodonSequence.
func (s *CodonSequence) Char(i int) string {
	return string(s.seq[i])
}

// ProtChar returns a single amino acid from the prot field of CodonSequence.
func (s *CodonSequence) ProtChar(i int) string {
	return string(s.prot[i])
}

// Codon returns a single codon 3 nucleotides long from the codons field of
// CodonSequence.
func (s *CodonSequence) Codon(i int) string {
	return string(s.codons[i])
}

/* The following two methods are setters for sequence fields in CodonSequence.
   Note that there is not method to set a protein sequence in the prot field.
   Because of the relationships between seq, prot, and codons, it is impossible
   to compute the values of seq and codons from the protein sequence alone.
   Although a protein sequence can be set literally, this is not recommended as
   there is no way to ensure that the relationships between seq, prot, and
   codons are maintained.
*/

// SetSequence assigns a nucleotide sequence to the seq field of CodonSequence.
// It also automatically fills the codons and prot fields by splitting the
// nucleotide sequence into triplets and translating each codon into its
// corresponding amino acid using the standard genetic code respectively.
func (s *CodonSequence) SetSequence(seq string) {
	for i := 0; i < len(seq); i += 3 {
		s.codons = append(s.codons, string(seq[i:i+3]))
	}
	s.prot = Translate(seq).String()
}

// SetCodons assigns a nucleotide sequence delimited by codon to the codons
// field of CodonSequence. It also automatically fills the seq and prot
// fields by joining the codons into a single continuous string and
// translating each codon into its corresponding amino acid using the
// standard genetic code respectively.
func (s *CodonSequence) SetCodons(seq []string) {
	s.codons = seq
	s.seq = strings.Join(seq, "")
	s.prot = Translate(s.seq).String()
}

// UngappedCoords returns the positions in the sequence where the character
// does not match the gap character.
func (s *CodonSequence) UngappedCoords(gapChar string) (colCoords []int) {
	set := make(map[int]struct{})
	for j := 0; j < len(s.seq); j++ {
		if string(s.seq[j]) != gapChar {
			set[j] = struct{}{}
		}
	}
	for key := range set {
		colCoords = append(colCoords, key)
	}
	sort.Ints(colCoords)
	return
}

// UngappedPositionSlice returns a slice that counts only over characters
// that does not match the gap character in the sequence.
// If a character matches the gap character, -1 is inserted instead of the
// ungapped count.
func (s *CodonSequence) UngappedPositionSlice(gapChar string) (arr []int) {
	cnt := 0
	for j := 0; j < len(s.seq); j++ {
		if string(s.seq[j]) != gapChar {
			arr = append(arr, cnt)
			cnt++
		} else {
			arr = append(arr, -1)
		}
	}
	return
}

// ToUpper changes the case of the sequence to all uppercase letters.
func (s *CodonSequence) ToUpper() {
	s.seq = strings.ToUpper(s.seq)
	s.prot = strings.ToUpper(s.prot)
	for i := 0; i < len(s.seq); i++ {
		s.codons[i] = strings.ToUpper(s.codons[i])
	}
}

// ToLower changes the case of the sequence to all lowercase letters.
func (s *CodonSequence) ToLower() {
	s.seq = strings.ToLower(s.seq)
	s.prot = strings.ToLower(s.prot)
	for i := 0; i < len(s.seq); i++ {
		s.codons[i] = strings.ToLower(s.codons[i])
	}
}

// sequence constants

var bases = [4]string{"T", "C", "A", "G"}
var codons = [64]string{
	"TTT", "TTC", "TTA", "TTG",
	"TCT", "TCC", "TCA", "TCG",
	"TAT", "TAC", "TAA", "TAG",
	"TGT", "TGC", "TGA", "TGG",
	"CTT", "CTC", "CTA", "CTG",
	"CCT", "CCC", "CCA", "CCG",
	"CAT", "CAC", "CAA", "CAG",
	"CGT", "CGC", "CGA", "CGG",
	"ATT", "ATC", "ATA", "ATG",
	"ACT", "ACC", "ACA", "ACG",
	"AAT", "AAC", "AAA", "AAG",
	"AGT", "AGC", "AGA", "AGG",
	"GTT", "GTC", "GTA", "GTG",
	"GCT", "GCC", "GCA", "GCG",
	"GAT", "GAC", "GAA", "GAG",
	"GGT", "GGC", "GGA", "GGG",
}
var stopCodons = [3]string{"TGA", "TAG", "TAA"}
var aminoAcids = [20]string{
	"A",
	"R",
	"N",
	"D",
	"C",
	"Q",
	"E",
	"G",
	"H",
	"I",
	"L",
	"K",
	"M",
	"F",
	"P",
	"S",
	"T",
	"W",
	"Y",
	"V",
}
var geneticCode = map[string]string{
	"TTT": "F",
	"TTC": "F",
	"TTA": "L",
	"TTG": "L",
	"TCT": "L",
	"TCC": "L",
	"TCA": "L",
	"TCG": "L",
	"TAT": "I",
	"TAC": "I",
	"TAA": "I",
	"TAG": "M",
	"TGT": "V",
	"TGC": "V",
	"TGA": "V",
	"TGG": "V",
	"CTT": "S",
	"CTC": "S",
	"CTA": "S",
	"CTG": "S",
	"CCT": "P",
	"CCC": "P",
	"CCA": "P",
	"CCG": "P",
	"CAT": "T",
	"CAC": "T",
	"CAA": "T",
	"CAG": "T",
	"CGT": "A",
	"CGC": "A",
	"CGA": "A",
	"CGG": "A",
	"ATT": "Y",
	"ATC": "Y",
	"ATA": "*",
	"ATG": "*",
	"ACT": "H",
	"ACC": "H",
	"ACA": "Q",
	"ACG": "Q",
	"AAT": "N",
	"AAC": "N",
	"AAA": "K",
	"AAG": "K",
	"AGT": "D",
	"AGC": "D",
	"AGA": "E",
	"AGG": "E",
	"GTT": "C",
	"GTC": "C",
	"GTA": "*",
	"GTG": "W",
	"GCT": "R",
	"GCC": "R",
	"GCA": "R",
	"GCG": "R",
	"GAT": "S",
	"GAC": "S",
	"GAA": "R",
	"GAG": "R",
	"GGT": "G",
	"GGC": "G",
	"GGA": "G",
	"GGG": "G",
	"---": "-",
}
<commit_msg>Comparing to byte version of gapChar instead of tpe converting selected character.<commit_after>package main

import (
	"sort"
	"strings"
)

// Sequence is an interface for single character sequences stored as a string
// and multi-character sequences stored as a slice.
type Sequence interface {
	ID() string
	Title() string
	Sequence() string
	Char(int) string
	SetSequence(string)
	ToUpper()
	ToLower()
	UngappedCoords(string) []int
	UngappedPositionSlice(string) []int
}

// CharSequence struct for storing single-character biological sequences such
// as nucleotides and single-letter amino acids. However, any sequence that
// whose element can be represented as a single string character can be stored
// in CharSequence.
type CharSequence struct {
	id    string
	title string
	seq   string
}

// ID returns the id field of CharSequence.
func (s *CharSequence) ID() string {
	return s.id
}

// Title returns the title field of CharSequence.
func (s *CharSequence) Title() string {
	return s.title
}

// Sequence returns the seq field of CharSequence.
func (s *CharSequence) Sequence() string {
	return s.seq
}

// Char returns a single character from the seq field of CharSequence.
func (s *CharSequence) Char(i int) string {
	return string(s.seq[i])
}

// SetSequence assigns a string to the seq field of CharSequence.
func (s *CharSequence) SetSequence(seq string) {
	s.seq = seq
}

// UngappedCoords returns the positions in the sequence where the character
// does not match the gap character.
func (s *CharSequence) UngappedCoords(gapChar string) (colCoords []int) {
	set := make(map[int]struct{})
	gapByte := []byte(gapChar)[0]
	for j := 0; j < len(s.seq); j++ {
		if s.seq[j] != gapByte {
			set[j] = struct{}{}
		}
	}
	for key := range set {
		colCoords = append(colCoords, key)
	}
	sort.Ints(colCoords)
	return
}

// UngappedPositionSlice returns a slice that counts only over characters
// that does not match the gap character in the sequence.
// If a character matches the gap character, -1 is inserted instead of the
// ungapped count.
func (s *CharSequence) UngappedPositionSlice(gapChar string) (arr []int) {
	gapByte := []byte(gapChar)[0]
	cnt := 0
	for j := 0; j < len(s.seq); j++ {
		if s.seq[j] != gapByte {
			arr = append(arr, cnt)
			cnt++
		} else {
			arr = append(arr, -1)
		}
	}
	return
}

// ToUpper changes the case of the sequence to all uppercase letters.
func (s *CharSequence) ToUpper() {
	s.seq = strings.ToUpper(s.seq)
}

// ToLower changes the case of the sequence to all lowercase letters.
func (s *CharSequence) ToLower() {
	s.seq = strings.ToLower(s.seq)
}

// CodonSequence is a struct for specifically designed for triplet nucleotide
// codon sequences. It embeds the CharSequence struct which also gives it
// id, title and seq fields. Additionally, CodonSequence has a prot field which
// stores a string and a codon string field which stores a slice of strings.
// The seq, prot and codons fields follow a positional correspondence.
// The first item in the codons slice translates to the first character
// in the prot string. The first item in the codons slice is equal to
// the first three characters of the seq string. This codon-seq correspondence
// should be consistent across the entire sequence.
type CodonSequence struct {
	CharSequence
	prot   string
	codons []string
}

// NewCodonSequence is a constructor that creates a new CodonSequence where
// prot and codons field values are automatically computed from the provided
// nucleotide sequence.
func NewCodonSequence(id, title, seq string) *CodonSequence {
	if len(seq)%3 == 0 {
		panic("seq length not divisible by 3")
	}
	s := new(CodonSequence)
	s.id = id
	s.title = title
	s.SetSequence(seq)
	return s
}

// ID returns the id field of CodonSequence.
func (s *CodonSequence) ID() string {
	return s.id
}

// Title returns the title field of CodonSequence.
func (s *CodonSequence) Title() string {
	return s.title
}

// Sequence returns the seq field of CodonSequence. The seq field contains
// a nucleotide sequence stored as a string.
func (s *CodonSequence) Sequence() string {
	return s.seq
}

// Codons returns the codon field of CodonSequence. The codon field
// contains a nucleotide sequence delimited by codon. This is stored
// as a slice of 3-character strings.
func (s *CodonSequence) Codons() []string {
	return s.codons
}

// Prot returns the prot field of CodonSequence. The prot field
// contains the translated amino acid sequence based on the seq
// field using the standard genetic code. The amino acid sequence
// is encoded as single-character amino acids and stored as a
// string.
func (s *CodonSequence) Prot() string {
	return s.prot
}

// Char returns a single nucleotide from the seq field of CodonSequence.
func (s *CodonSequence) Char(i int) string {
	return string(s.seq[i])
}

// ProtChar returns a single amino acid from the prot field of CodonSequence.
func (s *CodonSequence) ProtChar(i int) string {
	return string(s.prot[i])
}

// Codon returns a single codon 3 nucleotides long from the codons field of
// CodonSequence.
func (s *CodonSequence) Codon(i int) string {
	return string(s.codons[i])
}

/* The following two methods are setters for sequence fields in CodonSequence.
   Note that there is not method to set a protein sequence in the prot field.
   Because of the relationships between seq, prot, and codons, it is impossible
   to compute the values of seq and codons from the protein sequence alone.
   Although a protein sequence can be set literally, this is not recommended as
   there is no way to ensure that the relationships between seq, prot, and
   codons are maintained.
*/

// SetSequence assigns a nucleotide sequence to the seq field of CodonSequence.
// It also automatically fills the codons and prot fields by splitting the
// nucleotide sequence into triplets and translating each codon into its
// corresponding amino acid using the standard genetic code respectively.
func (s *CodonSequence) SetSequence(seq string) {
	for i := 0; i < len(seq); i += 3 {
		s.codons = append(s.codons, string(seq[i:i+3]))
	}
	s.prot = Translate(seq).String()
}

// SetCodons assigns a nucleotide sequence delimited by codon to the codons
// field of CodonSequence. It also automatically fills the seq and prot
// fields by joining the codons into a single continuous string and
// translating each codon into its corresponding amino acid using the
// standard genetic code respectively.
func (s *CodonSequence) SetCodons(seq []string) {
	s.codons = seq
	s.seq = strings.Join(seq, "")
	s.prot = Translate(s.seq).String()
}

// UngappedCoords returns the positions in the sequence where the character
// does not match the gap character.
func (s *CodonSequence) UngappedCoords(gapChar string) (colCoords []int) {
	set := make(map[int]struct{})
	gapByte := []byte(gapChar)[0]
	for j := 0; j < len(s.seq); j++ {
		if s.seq[j] != gapByte {
			set[j] = struct{}{}
		}
	}
	for key := range set {
		colCoords = append(colCoords, key)
	}
	sort.Ints(colCoords)
	return
}

// UngappedPositionSlice returns a slice that counts only over characters
// that does not match the gap character in the sequence.
// If a character matches the gap character, -1 is inserted instead of the
// ungapped count.
func (s *CodonSequence) UngappedPositionSlice(gapChar string) (arr []int) {
	cnt := 0
	gapByte := []byte(gapChar)[0]
	for j := 0; j < len(s.seq); j++ {
		if s.seq[j] != gapByte {
			arr = append(arr, cnt)
			cnt++
		} else {
			arr = append(arr, -1)
		}
	}
	return
}

// ToUpper changes the case of the sequence to all uppercase letters.
func (s *CodonSequence) ToUpper() {
	s.seq = strings.ToUpper(s.seq)
	s.prot = strings.ToUpper(s.prot)
	for i := 0; i < len(s.seq); i++ {
		s.codons[i] = strings.ToUpper(s.codons[i])
	}
}

// ToLower changes the case of the sequence to all lowercase letters.
func (s *CodonSequence) ToLower() {
	s.seq = strings.ToLower(s.seq)
	s.prot = strings.ToLower(s.prot)
	for i := 0; i < len(s.seq); i++ {
		s.codons[i] = strings.ToLower(s.codons[i])
	}
}

// sequence constants

var bases = [4]string{"T", "C", "A", "G"}
var codons = [64]string{
	"TTT", "TTC", "TTA", "TTG",
	"TCT", "TCC", "TCA", "TCG",
	"TAT", "TAC", "TAA", "TAG",
	"TGT", "TGC", "TGA", "TGG",
	"CTT", "CTC", "CTA", "CTG",
	"CCT", "CCC", "CCA", "CCG",
	"CAT", "CAC", "CAA", "CAG",
	"CGT", "CGC", "CGA", "CGG",
	"ATT", "ATC", "ATA", "ATG",
	"ACT", "ACC", "ACA", "ACG",
	"AAT", "AAC", "AAA", "AAG",
	"AGT", "AGC", "AGA", "AGG",
	"GTT", "GTC", "GTA", "GTG",
	"GCT", "GCC", "GCA", "GCG",
	"GAT", "GAC", "GAA", "GAG",
	"GGT", "GGC", "GGA", "GGG",
}
var stopCodons = [3]string{"TGA", "TAG", "TAA"}
var aminoAcids = [20]string{
	"A",
	"R",
	"N",
	"D",
	"C",
	"Q",
	"E",
	"G",
	"H",
	"I",
	"L",
	"K",
	"M",
	"F",
	"P",
	"S",
	"T",
	"W",
	"Y",
	"V",
}
var geneticCode = map[string]string{
	"TTT": "F",
	"TTC": "F",
	"TTA": "L",
	"TTG": "L",
	"TCT": "L",
	"TCC": "L",
	"TCA": "L",
	"TCG": "L",
	"TAT": "I",
	"TAC": "I",
	"TAA": "I",
	"TAG": "M",
	"TGT": "V",
	"TGC": "V",
	"TGA": "V",
	"TGG": "V",
	"CTT": "S",
	"CTC": "S",
	"CTA": "S",
	"CTG": "S",
	"CCT": "P",
	"CCC": "P",
	"CCA": "P",
	"CCG": "P",
	"CAT": "T",
	"CAC": "T",
	"CAA": "T",
	"CAG": "T",
	"CGT": "A",
	"CGC": "A",
	"CGA": "A",
	"CGG": "A",
	"ATT": "Y",
	"ATC": "Y",
	"ATA": "*",
	"ATG": "*",
	"ACT": "H",
	"ACC": "H",
	"ACA": "Q",
	"ACG": "Q",
	"AAT": "N",
	"AAC": "N",
	"AAA": "K",
	"AAG": "K",
	"AGT": "D",
	"AGC": "D",
	"AGA": "E",
	"AGG": "E",
	"GTT": "C",
	"GTC": "C",
	"GTA": "*",
	"GTG": "W",
	"GCT": "R",
	"GCC": "R",
	"GCA": "R",
	"GCG": "R",
	"GAT": "S",
	"GAC": "S",
	"GAA": "R",
	"GAG": "R",
	"GGT": "G",
	"GGC": "G",
	"GGA": "G",
	"GGG": "G",
	"---": "-",
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"sort"
	"strings"
)

// Sequence is an interface for single character sequences stored as a string
// and multi-character sequences stored as a slice.
type Sequence interface {
	ID() string
	Title() string
	Sequence() string
	Char(int) string
	SetSequence(string)
	ToUpper()
	ToLower()
	UngappedCoords(string) []int
	UngappedPositionSlice(string) []int
}

// CharSequence struct for storing single-character biological sequences such
// as nucleotides and single-letter amino acids. However, any sequence that
// whose element can be represented as a single string character can be stored
// in CharSequence.
type CharSequence struct {
	id    string
	title string
	seq   string
}

// ID returns the id field of CharSequence.
func (s *CharSequence) ID() string {
	return s.id
}

// Title returns the title field of CharSequence.
func (s *CharSequence) Title() string {
	return s.title
}

// Sequence returns the seq field of CharSequence.
func (s *CharSequence) Sequence() string {
	return s.seq
}

// Char returns a single character from the seq field of CharSequence.
func (s *CharSequence) Char(i int) string {
	return string(s.seq[i])
}

// SetSequence assigns a string to the seq field of CharSequence.
func (s *CharSequence) SetSequence(seq string) {
	s.seq = seq
}

// UngappedCoords returns the positions in the sequence where the character
// does not match the gap character.
func (s *CharSequence) UngappedCoords(gapChar string) (colCoords []int) {
	set := make(map[int]struct{})
	gapByte := []byte(gapChar)[0]
	for j := 0; j < len(s.seq); j++ {
		if s.seq[j] != gapByte {
			set[j] = struct{}{}
		}
	}
	for key := range set {
		colCoords = append(colCoords, key)
	}
	sort.Ints(colCoords)
	return
}

// UngappedPositionSlice returns a slice that counts only over characters
// that does not match the gap character in the sequence.
// If a character matches the gap character, -1 is inserted instead of the
// ungapped count.
func (s *CharSequence) UngappedPositionSlice(gapChar string) (arr []int) {
	gapByte := []byte(gapChar)[0]
	cnt := 0
	for j := 0; j < len(s.seq); j++ {
		if s.seq[j] != gapByte {
			arr = append(arr, cnt)
			cnt++
		} else {
			arr = append(arr, -1)
		}
	}
	return
}

// ToUpper changes the case of the sequence to all uppercase letters.
func (s *CharSequence) ToUpper() {
	s.seq = strings.ToUpper(s.seq)
}

// ToLower changes the case of the sequence to all lowercase letters.
func (s *CharSequence) ToLower() {
	s.seq = strings.ToLower(s.seq)
}

// CodonSequence is a struct for specifically designed for triplet nucleotide
// codon sequences. It embeds the CharSequence struct which also gives it
// id, title and seq fields. Additionally, CodonSequence has a prot field which
// stores a string and a codon string field which stores a slice of strings.
// The seq, prot and codons fields follow a positional correspondence.
// The first item in the codons slice translates to the first character
// in the prot string. The first item in the codons slice is equal to
// the first three characters of the seq string. This codon-seq correspondence
// should be consistent across the entire sequence.
type CodonSequence struct {
	CharSequence
	prot   string
	codons []string
}

// NewCodonSequence is a constructor that creates a new CodonSequence where
// prot and codons field values are automatically computed from the provided
// nucleotide sequence.
func NewCodonSequence(id, title, seq string) *CodonSequence {
	if len(seq)%3 != 0 {
		panic(fmt.Sprintf("Given seq's length (%d) not divisible by 3", len(seq)))
	}
	s := new(CodonSequence)
	s.id = id
	s.title = title
	s.SetSequence(seq)
	return s
}

// ID returns the id field of CodonSequence.
func (s *CodonSequence) ID() string {
	return s.id
}

// Title returns the title field of CodonSequence.
func (s *CodonSequence) Title() string {
	return s.title
}

// Sequence returns the seq field of CodonSequence. The seq field contains
// a nucleotide sequence stored as a string.
func (s *CodonSequence) Sequence() string {
	return s.seq
}

// Codons returns the codon field of CodonSequence. The codon field
// contains a nucleotide sequence delimited by codon. This is stored
// as a slice of 3-character strings.
func (s *CodonSequence) Codons() []string {
	return s.codons
}

// Prot returns the prot field of CodonSequence. The prot field
// contains the translated amino acid sequence based on the seq
// field using the standard genetic code. The amino acid sequence
// is encoded as single-character amino acids and stored as a
// string.
func (s *CodonSequence) Prot() string {
	return s.prot
}

// Char returns a single nucleotide from the seq field of CodonSequence.
func (s *CodonSequence) Char(i int) string {
	return string(s.seq[i])
}

// ProtChar returns a single amino acid from the prot field of CodonSequence.
func (s *CodonSequence) ProtChar(i int) string {
	return string(s.prot[i])
}

// Codon returns a single codon 3 nucleotides long from the codons field of
// CodonSequence.
func (s *CodonSequence) Codon(i int) string {
	return string(s.codons[i])
}

/* The following two methods are setters for sequence fields in CodonSequence.
   Note that there is not method to set a protein sequence in the prot field.
   Because of the relationships between seq, prot, and codons, it is impossible
   to compute the values of seq and codons from the protein sequence alone.
   Although a protein sequence can be set literally, this is not recommended as
   there is no way to ensure that the relationships between seq, prot, and
   codons are maintained.
*/

// SetSequence assigns a nucleotide sequence to the seq field of CodonSequence.
// It also automatically fills the codons and prot fields by splitting the
// nucleotide sequence into triplets and translating each codon into its
// corresponding amino acid using the standard genetic code respectively.
func (s *CodonSequence) SetSequence(seq string) {
	for i := 0; i < len(seq); i += 3 {
		s.codons = append(s.codons, string(seq[i:i+3]))
	}
	s.prot = Translate(seq).String()
}

// SetCodons assigns a nucleotide sequence delimited by codon to the codons
// field of CodonSequence. It also automatically fills the seq and prot
// fields by joining the codons into a single continuous string and
// translating each codon into its corresponding amino acid using the
// standard genetic code respectively.
func (s *CodonSequence) SetCodons(seq []string) {
	s.codons = seq
	s.seq = strings.Join(seq, "")
	s.prot = Translate(s.seq).String()
}

// UngappedCoords returns the positions in the sequence where the character
// does not match the gap character.
func (s *CodonSequence) UngappedCoords(gapChar string) (colCoords []int) {
	if len(gapChar)%3 != 0 {
		panic(fmt.Sprintf("Length of given gapChar \"%s\" is not equal to 3", gapChar))
	}
	set := make(map[int]struct{})
	for j := 0; j < len(s.codons); j++ {
		if s.codons[j] != gapChar {
			set[j] = struct{}{}
		}
	}
	for key := range set {
		colCoords = append(colCoords, key)
	}
	sort.Ints(colCoords)
	return
}

// UngappedPositionSlice returns a slice that counts only over characters
// that does not match the gap character in the sequence.
// If a character matches the gap character, -1 is inserted instead of the
// ungapped count.
func (s *CodonSequence) UngappedPositionSlice(gapChar string) (arr []int) {
	if len(gapChar)%3 != 0 {
		panic(fmt.Sprintf("Length of given gapChar \"%s\" is not equal to 3", gapChar))
	}
	cnt := 0
	for j := 0; j < len(s.codons); j++ {
		if s.codons[j] != gapChar {
			arr = append(arr, cnt)
			cnt++
		} else {
			arr = append(arr, -1)
		}
	}
	return
}

// ToUpper changes the case of the sequence to all uppercase letters.
func (s *CodonSequence) ToUpper() {
	s.seq = strings.ToUpper(s.seq)
	s.prot = strings.ToUpper(s.prot)
	for i := 0; i < len(s.seq); i++ {
		s.codons[i] = strings.ToUpper(s.codons[i])
	}
}

// ToLower changes the case of the sequence to all lowercase letters.
func (s *CodonSequence) ToLower() {
	s.seq = strings.ToLower(s.seq)
	s.prot = strings.ToLower(s.prot)
	for i := 0; i < len(s.seq); i++ {
		s.codons[i] = strings.ToLower(s.codons[i])
	}
}

// sequence constants

var bases = [4]string{"T", "C", "A", "G"}
var codons = [64]string{
	"TTT", "TTC", "TTA", "TTG",
	"TCT", "TCC", "TCA", "TCG",
	"TAT", "TAC", "TAA", "TAG",
	"TGT", "TGC", "TGA", "TGG",
	"CTT", "CTC", "CTA", "CTG",
	"CCT", "CCC", "CCA", "CCG",
	"CAT", "CAC", "CAA", "CAG",
	"CGT", "CGC", "CGA", "CGG",
	"ATT", "ATC", "ATA", "ATG",
	"ACT", "ACC", "ACA", "ACG",
	"AAT", "AAC", "AAA", "AAG",
	"AGT", "AGC", "AGA", "AGG",
	"GTT", "GTC", "GTA", "GTG",
	"GCT", "GCC", "GCA", "GCG",
	"GAT", "GAC", "GAA", "GAG",
	"GGT", "GGC", "GGA", "GGG",
}
var stopCodons = [3]string{"TGA", "TAG", "TAA"}
var aminoAcids = [20]string{
	"A",
	"R",
	"N",
	"D",
	"C",
	"Q",
	"E",
	"G",
	"H",
	"I",
	"L",
	"K",
	"M",
	"F",
	"P",
	"S",
	"T",
	"W",
	"Y",
	"V",
}
var geneticCode = map[string]string{
	"TTT": "F",
	"TTC": "F",
	"TTA": "L",
	"TTG": "L",
	"TCT": "L",
	"TCC": "L",
	"TCA": "L",
	"TCG": "L",
	"TAT": "I",
	"TAC": "I",
	"TAA": "I",
	"TAG": "M",
	"TGT": "V",
	"TGC": "V",
	"TGA": "V",
	"TGG": "V",
	"CTT": "S",
	"CTC": "S",
	"CTA": "S",
	"CTG": "S",
	"CCT": "P",
	"CCC": "P",
	"CCA": "P",
	"CCG": "P",
	"CAT": "T",
	"CAC": "T",
	"CAA": "T",
	"CAG": "T",
	"CGT": "A",
	"CGC": "A",
	"CGA": "A",
	"CGG": "A",
	"ATT": "Y",
	"ATC": "Y",
	"ATA": "*",
	"ATG": "*",
	"ACT": "H",
	"ACC": "H",
	"ACA": "Q",
	"ACG": "Q",
	"AAT": "N",
	"AAC": "N",
	"AAA": "K",
	"AAG": "K",
	"AGT": "D",
	"AGC": "D",
	"AGA": "E",
	"AGG": "E",
	"GTT": "C",
	"GTC": "C",
	"GTA": "*",
	"GTG": "W",
	"GCT": "R",
	"GCC": "R",
	"GCA": "R",
	"GCG": "R",
	"GAT": "S",
	"GAC": "S",
	"GAA": "R",
	"GAG": "R",
	"GGT": "G",
	"GGC": "G",
	"GGA": "G",
	"GGG": "G",
	"---": "-",
}
<commit_msg>Fixes bug in SetSequence<commit_after>package main

import (
	"fmt"
	"sort"
	"strings"
)

// Sequence is an interface for single character sequences stored as a string
// and multi-character sequences stored as a slice.
type Sequence interface {
	ID() string
	Title() string
	Sequence() string
	Char(int) string
	SetSequence(string)
	ToUpper()
	ToLower()
	UngappedCoords(string) []int
	UngappedPositionSlice(string) []int
}

// CharSequence struct for storing single-character biological sequences such
// as nucleotides and single-letter amino acids. However, any sequence that
// whose element can be represented as a single string character can be stored
// in CharSequence.
type CharSequence struct {
	id    string
	title string
	seq   string
}

// ID returns the id field of CharSequence.
func (s *CharSequence) ID() string {
	return s.id
}

// Title returns the title field of CharSequence.
func (s *CharSequence) Title() string {
	return s.title
}

// Sequence returns the seq field of CharSequence.
func (s *CharSequence) Sequence() string {
	return s.seq
}

// Char returns a single character from the seq field of CharSequence.
func (s *CharSequence) Char(i int) string {
	return string(s.seq[i])
}

// SetSequence assigns a string to the seq field of CharSequence.
func (s *CharSequence) SetSequence(seq string) {
	s.seq = seq
}

// UngappedCoords returns the positions in the sequence where the character
// does not match the gap character.
func (s *CharSequence) UngappedCoords(gapChar string) (colCoords []int) {
	set := make(map[int]struct{})
	gapByte := []byte(gapChar)[0]
	for j := 0; j < len(s.seq); j++ {
		if s.seq[j] != gapByte {
			set[j] = struct{}{}
		}
	}
	for key := range set {
		colCoords = append(colCoords, key)
	}
	sort.Ints(colCoords)
	return
}

// UngappedPositionSlice returns a slice that counts only over characters
// that does not match the gap character in the sequence.
// If a character matches the gap character, -1 is inserted instead of the
// ungapped count.
func (s *CharSequence) UngappedPositionSlice(gapChar string) (arr []int) {
	gapByte := []byte(gapChar)[0]
	cnt := 0
	for j := 0; j < len(s.seq); j++ {
		if s.seq[j] != gapByte {
			arr = append(arr, cnt)
			cnt++
		} else {
			arr = append(arr, -1)
		}
	}
	return
}

// ToUpper changes the case of the sequence to all uppercase letters.
func (s *CharSequence) ToUpper() {
	s.seq = strings.ToUpper(s.seq)
}

// ToLower changes the case of the sequence to all lowercase letters.
func (s *CharSequence) ToLower() {
	s.seq = strings.ToLower(s.seq)
}

// CodonSequence is a struct for specifically designed for triplet nucleotide
// codon sequences. It embeds the CharSequence struct which also gives it
// id, title and seq fields. Additionally, CodonSequence has a prot field which
// stores a string and a codon string field which stores a slice of strings.
// The seq, prot and codons fields follow a positional correspondence.
// The first item in the codons slice translates to the first character
// in the prot string. The first item in the codons slice is equal to
// the first three characters of the seq string. This codon-seq correspondence
// should be consistent across the entire sequence.
type CodonSequence struct {
	CharSequence
	prot   string
	codons []string
}

// NewCodonSequence is a constructor that creates a new CodonSequence where
// prot and codons field values are automatically computed from the provided
// nucleotide sequence.
func NewCodonSequence(id, title, seq string) *CodonSequence {
	if len(seq)%3 != 0 {
		panic(fmt.Sprintf("Given seq's length (%d) not divisible by 3", len(seq)))
	}
	s := new(CodonSequence)
	s.id = id
	s.title = title
	s.SetSequence(seq)
	return s
}

// ID returns the id field of CodonSequence.
func (s *CodonSequence) ID() string {
	return s.id
}

// Title returns the title field of CodonSequence.
func (s *CodonSequence) Title() string {
	return s.title
}

// Sequence returns the seq field of CodonSequence. The seq field contains
// a nucleotide sequence stored as a string.
func (s *CodonSequence) Sequence() string {
	return s.seq
}

// Codons returns the codon field of CodonSequence. The codon field
// contains a nucleotide sequence delimited by codon. This is stored
// as a slice of 3-character strings.
func (s *CodonSequence) Codons() []string {
	return s.codons
}

// Prot returns the prot field of CodonSequence. The prot field
// contains the translated amino acid sequence based on the seq
// field using the standard genetic code. The amino acid sequence
// is encoded as single-character amino acids and stored as a
// string.
func (s *CodonSequence) Prot() string {
	return s.prot
}

// Char returns a single nucleotide from the seq field of CodonSequence.
func (s *CodonSequence) Char(i int) string {
	return string(s.seq[i])
}

// ProtChar returns a single amino acid from the prot field of CodonSequence.
func (s *CodonSequence) ProtChar(i int) string {
	return string(s.prot[i])
}

// Codon returns a single codon 3 nucleotides long from the codons field of
// CodonSequence.
func (s *CodonSequence) Codon(i int) string {
	return string(s.codons[i])
}

/* The following two methods are setters for sequence fields in CodonSequence.
   Note that there is not method to set a protein sequence in the prot field.
   Because of the relationships between seq, prot, and codons, it is impossible
   to compute the values of seq and codons from the protein sequence alone.
   Although a protein sequence can be set literally, this is not recommended as
   there is no way to ensure that the relationships between seq, prot, and
   codons are maintained.
*/

// SetSequence assigns a nucleotide sequence to the seq field of CodonSequence.
// It also automatically fills the codons and prot fields by splitting the
// nucleotide sequence into triplets and translating each codon into its
// corresponding amino acid using the standard genetic code respectively.
func (s *CodonSequence) SetSequence(seq string) {
	if len(seq)%3 != 0 {
		panic(fmt.Sprintf("Length of given seq \"%s\" is not divisible by 3", seq))
	}
	s.seq = seq
	for i := 0; i < len(seq); i += 3 {
		s.codons = append(s.codons, string(seq[i:i+3]))
	}
	s.prot = Translate(seq).String()
}

// SetCodons assigns a nucleotide sequence delimited by codon to the codons
// field of CodonSequence. It also automatically fills the seq and prot
// fields by joining the codons into a single continuous string and
// translating each codon into its corresponding amino acid using the
// standard genetic code respectively.
func (s *CodonSequence) SetCodons(seq []string) {
	s.codons = seq
	s.seq = strings.Join(seq, "")
	s.prot = Translate(s.seq).String()
}

// UngappedCoords returns the positions in the sequence where the character
// does not match the gap character.
func (s *CodonSequence) UngappedCoords(gapChar string) (colCoords []int) {
	if len(gapChar)%3 != 0 {
		panic(fmt.Sprintf("Length of given gapChar \"%s\" is not equal to 3", gapChar))
	}
	set := make(map[int]struct{})
	for j := 0; j < len(s.codons); j++ {
		if s.codons[j] != gapChar {
			set[j] = struct{}{}
		}
	}
	for key := range set {
		colCoords = append(colCoords, key)
	}
	sort.Ints(colCoords)
	return
}

// UngappedPositionSlice returns a slice that counts only over characters
// that does not match the gap character in the sequence.
// If a character matches the gap character, -1 is inserted instead of the
// ungapped count.
func (s *CodonSequence) UngappedPositionSlice(gapChar string) (arr []int) {
	if len(gapChar)%3 != 0 {
		panic(fmt.Sprintf("Length of given gapChar \"%s\" is not equal to 3", gapChar))
	}
	cnt := 0
	for j := 0; j < len(s.codons); j++ {
		if s.codons[j] != gapChar {
			arr = append(arr, cnt)
			cnt++
		} else {
			arr = append(arr, -1)
		}
	}
	return
}

// ToUpper changes the case of the sequence to all uppercase letters.
func (s *CodonSequence) ToUpper() {
	s.seq = strings.ToUpper(s.seq)
	s.prot = strings.ToUpper(s.prot)
	for i := 0; i < len(s.seq); i++ {
		s.codons[i] = strings.ToUpper(s.codons[i])
	}
}

// ToLower changes the case of the sequence to all lowercase letters.
func (s *CodonSequence) ToLower() {
	s.seq = strings.ToLower(s.seq)
	s.prot = strings.ToLower(s.prot)
	for i := 0; i < len(s.seq); i++ {
		s.codons[i] = strings.ToLower(s.codons[i])
	}
}

// sequence constants

var bases = [4]string{"T", "C", "A", "G"}
var codons = [64]string{
	"TTT", "TTC", "TTA", "TTG",
	"TCT", "TCC", "TCA", "TCG",
	"TAT", "TAC", "TAA", "TAG",
	"TGT", "TGC", "TGA", "TGG",
	"CTT", "CTC", "CTA", "CTG",
	"CCT", "CCC", "CCA", "CCG",
	"CAT", "CAC", "CAA", "CAG",
	"CGT", "CGC", "CGA", "CGG",
	"ATT", "ATC", "ATA", "ATG",
	"ACT", "ACC", "ACA", "ACG",
	"AAT", "AAC", "AAA", "AAG",
	"AGT", "AGC", "AGA", "AGG",
	"GTT", "GTC", "GTA", "GTG",
	"GCT", "GCC", "GCA", "GCG",
	"GAT", "GAC", "GAA", "GAG",
	"GGT", "GGC", "GGA", "GGG",
}
var stopCodons = [3]string{"TGA", "TAG", "TAA"}
var aminoAcids = [20]string{
	"A",
	"R",
	"N",
	"D",
	"C",
	"Q",
	"E",
	"G",
	"H",
	"I",
	"L",
	"K",
	"M",
	"F",
	"P",
	"S",
	"T",
	"W",
	"Y",
	"V",
}
var geneticCode = map[string]string{
	"TTT": "F",
	"TTC": "F",
	"TTA": "L",
	"TTG": "L",
	"TCT": "L",
	"TCC": "L",
	"TCA": "L",
	"TCG": "L",
	"TAT": "I",
	"TAC": "I",
	"TAA": "I",
	"TAG": "M",
	"TGT": "V",
	"TGC": "V",
	"TGA": "V",
	"TGG": "V",
	"CTT": "S",
	"CTC": "S",
	"CTA": "S",
	"CTG": "S",
	"CCT": "P",
	"CCC": "P",
	"CCA": "P",
	"CCG": "P",
	"CAT": "T",
	"CAC": "T",
	"CAA": "T",
	"CAG": "T",
	"CGT": "A",
	"CGC": "A",
	"CGA": "A",
	"CGG": "A",
	"ATT": "Y",
	"ATC": "Y",
	"ATA": "*",
	"ATG": "*",
	"ACT": "H",
	"ACC": "H",
	"ACA": "Q",
	"ACG": "Q",
	"AAT": "N",
	"AAC": "N",
	"AAA": "K",
	"AAG": "K",
	"AGT": "D",
	"AGC": "D",
	"AGA": "E",
	"AGG": "E",
	"GTT": "C",
	"GTC": "C",
	"GTA": "*",
	"GTG": "W",
	"GCT": "R",
	"GCC": "R",
	"GCA": "R",
	"GCG": "R",
	"GAT": "S",
	"GAC": "S",
	"GAA": "R",
	"GAG": "R",
	"GGT": "G",
	"GGC": "G",
	"GGA": "G",
	"GGG": "G",
	"---": "-",
}
<|endoftext|>


<commit_before>package pubsub

import (
	"context"
	"errors"
	"fmt"
	"go.uber.org/zap"
	"strings"
	"sync"

	"cloud.google.com/go/pubsub"

	"github.com/cloudevents/sdk-go/pkg/cloudevents"
	cecontext "github.com/cloudevents/sdk-go/pkg/cloudevents/context"
	"github.com/cloudevents/sdk-go/pkg/cloudevents/transport"
	"github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/internal"
)

// Transport adheres to transport.Transport.
var _ transport.Transport = (*Transport)(nil)

const (
	TransportName = "Pub/Sub"
)

type subscriptionWithTopic struct {
	topicID        string
	subscriptionID string
}

// Transport acts as both a pubsub topic and a pubsub subscription .
type Transport struct {
	// Encoding
	Encoding Encoding

	// DefaultEncodingSelectionFn allows for other encoding selection strategies to be injected.
	DefaultEncodingSelectionFn EncodingSelector

	codec transport.Codec
	// Codec Mutex
	coMu sync.Mutex

	// PubSub

	// AllowCreateTopic controls if the transport can create a topic if it does
	// not exist.
	AllowCreateTopic bool

	// AllowCreateSubscription controls if the transport can create a
	// subscription if it does not exist.
	AllowCreateSubscription bool

	projectID      string
	topicID        string
	subscriptionID string

	gccMux sync.Mutex

	subscriptions []subscriptionWithTopic
	client        *pubsub.Client

	connectionsBySubscription map[string]*internal.Connection
	connectionsByTopic        map[string]*internal.Connection

	// Receiver
	Receiver transport.Receiver

	// Converter is invoked if the incoming transport receives an undecodable
	// message.
	Converter transport.Converter
}

// New creates a new pubsub transport.
func New(ctx context.Context, opts ...Option) (*Transport, error) {
	t := &Transport{}
	if err := t.applyOptions(opts...); err != nil {
		return nil, err
	}

	if t.client == nil {
		// Auth to pubsub.
		client, err := pubsub.NewClient(ctx, t.projectID)
		if err != nil {
			return nil, err
		}
		// Success.
		t.client = client
	}

	if t.connectionsBySubscription == nil {
		t.connectionsBySubscription = make(map[string]*internal.Connection, 0)
	}

	if t.connectionsByTopic == nil {
		t.connectionsByTopic = make(map[string]*internal.Connection, 0)
	}
	return t, nil
}

func (t *Transport) applyOptions(opts ...Option) error {
	for _, fn := range opts {
		if err := fn(t); err != nil {
			return err
		}
	}
	return nil
}

func (t *Transport) loadCodec(ctx context.Context) bool {
	if t.codec == nil {
		t.coMu.Lock()
		if t.DefaultEncodingSelectionFn != nil && t.Encoding != Default {
			logger := cecontext.LoggerFrom(ctx)
			logger.Warn("transport has a DefaultEncodingSelectionFn set but Encoding is not Default. DefaultEncodingSelectionFn will be ignored.")

			t.codec = &Codec{
				Encoding: t.Encoding,
			}
		} else {
			t.codec = &Codec{
				Encoding:                   t.Encoding,
				DefaultEncodingSelectionFn: t.DefaultEncodingSelectionFn,
			}
		}
		t.coMu.Unlock()
	}
	return true
}

func (t *Transport) getConnection(ctx context.Context, topic, subscription string) *internal.Connection {
	if subscription != "" {
		if conn, ok := t.connectionsBySubscription[subscription]; ok {
			return conn
		}
	}
	if topic != "" {
		if conn, ok := t.connectionsByTopic[topic]; ok {
			return conn
		}
	}

	return nil
}

func (t *Transport) getOrCreateConnection(ctx context.Context, topic, subscription string) *internal.Connection {
	t.gccMux.Lock()
	defer t.gccMux.Unlock()

	// Get.
	if conn := t.getConnection(ctx, topic, subscription); conn != nil {
		return conn
	}
	// Create.
	conn := &internal.Connection{
		AllowCreateSubscription: t.AllowCreateSubscription,
		AllowCreateTopic:        t.AllowCreateTopic,
		Client:                  t.client,
		ProjectID:               t.projectID,
		TopicID:                 topic,
		SubscriptionID:          subscription,
	}
	// Save for later.
	if subscription != "" {
		t.connectionsBySubscription[subscription] = conn
	}
	if topic != "" {
		t.connectionsByTopic[topic] = conn
	}

	return conn
}

// Send implements Transport.Send
func (t *Transport) Send(ctx context.Context, event cloudevents.Event) (context.Context, *cloudevents.Event, error) {
	// TODO populate response context properly.
	if ok := t.loadCodec(ctx); !ok {
		return ctx, nil, fmt.Errorf("unknown encoding set on transport: %d", t.Encoding)
	}

	topic := cecontext.TopicFrom(ctx)
	if topic == "" {
		topic = t.topicID
	}

	conn := t.getOrCreateConnection(ctx, topic, "")

	msg, err := t.codec.Encode(ctx, event)
	if err != nil {
		return ctx, nil, err
	}

	if m, ok := msg.(*Message); ok {
		respEvent, err := conn.Publish(ctx, &pubsub.Message{
			Attributes: m.Attributes,
			Data:       m.Data,
		})
		return ctx, respEvent, err
	}

	return ctx, nil, fmt.Errorf("failed to encode Event into a Message")
}

// SetReceiver implements Transport.SetReceiver
func (t *Transport) SetReceiver(r transport.Receiver) {
	t.Receiver = r
}

// SetConverter implements Transport.SetConverter
func (t *Transport) SetConverter(c transport.Converter) {
	t.Converter = c
}

// HasConverter implements Transport.HasConverter
func (t *Transport) HasConverter() bool {
	return t.Converter != nil
}

func (t *Transport) startSubscriber(ctx context.Context, sub subscriptionWithTopic, done func(error)) {
	logger := cecontext.LoggerFrom(ctx)
	logger.Infof("starting subscriber for Topic %q, Subscription %q", sub.topicID, sub.subscriptionID)
	conn := t.getOrCreateConnection(ctx, sub.topicID, sub.subscriptionID)

	logger.Info("conn is", conn)
	if conn == nil {
		err := fmt.Errorf("failed to find connection for Topic: %q, Subscription: %q", sub.topicID, sub.subscriptionID)
		done(err)
		return
	}
	// Ok, ready to start pulling.
	err := conn.Receive(ctx, func(ctx context.Context, m *pubsub.Message) {
		logger.Info("got an event!")
		msg := &Message{
			Attributes: m.Attributes,
			Data:       m.Data,
		}
		event, err := t.codec.Decode(ctx, msg)
		// If codec returns and error, try with the converter if it is set.
		if err != nil && t.HasConverter() {
			event, err = t.Converter.Convert(ctx, msg, err)
		}
		if err != nil {
			logger.Errorw("failed to decode message", zap.Error(err))
			m.Nack()
			return
		}

		if err := t.Receiver.Receive(ctx, *event, nil); err != nil {
			logger.Warnw("pubsub receiver return err", zap.Error(err))
			m.Nack()
			return
		}
		m.Ack()
	})
	done(err)
}

// StartReceiver implements Transport.StartReceiver
// NOTE: This is a blocking call.
func (t *Transport) StartReceiver(ctx context.Context) error {
	// Load the codec.
	if ok := t.loadCodec(ctx); !ok {
		return fmt.Errorf("unknown encoding set on transport: %d", t.Encoding)
	}

	cctx, cancel := context.WithCancel(ctx)
	defer cancel()
	n := len(t.subscriptions)

	// Make the channels for quit and errors.
	quit := make(chan struct{}, n)
	errc := make(chan error, n)

	// Start up each subscription.
	for _, sub := range t.subscriptions {
		go t.startSubscriber(cctx, sub, func(err error) {
			if err != nil {
				errc <- err
			} else {
				quit <- struct{}{}
			}
		})
	}

	// Collect errors and done calls until we have n of them.
	errs := []string(nil)
	for success := 0; success < n; success++ {
		var err error
		select {
		case <-ctx.Done(): // Block for parent context to finish.
			success--
		case err = <-errc: // Collect errors
		case <-quit:
		}
		if cancel != nil {
			// Stop all other subscriptions.
			cancel()
			cancel = nil
		}
		if err != nil {
			errs = append(errs, err.Error())
		}
	}

	close(quit)
	close(errc)

	return errors.New(strings.Join(errs, "\n"))
}
<commit_msg>Leaked a debug line. (#189)<commit_after>package pubsub

import (
	"context"
	"errors"
	"fmt"
	"go.uber.org/zap"
	"strings"
	"sync"

	"cloud.google.com/go/pubsub"

	"github.com/cloudevents/sdk-go/pkg/cloudevents"
	cecontext "github.com/cloudevents/sdk-go/pkg/cloudevents/context"
	"github.com/cloudevents/sdk-go/pkg/cloudevents/transport"
	"github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/internal"
)

// Transport adheres to transport.Transport.
var _ transport.Transport = (*Transport)(nil)

const (
	TransportName = "Pub/Sub"
)

type subscriptionWithTopic struct {
	topicID        string
	subscriptionID string
}

// Transport acts as both a pubsub topic and a pubsub subscription .
type Transport struct {
	// Encoding
	Encoding Encoding

	// DefaultEncodingSelectionFn allows for other encoding selection strategies to be injected.
	DefaultEncodingSelectionFn EncodingSelector

	codec transport.Codec
	// Codec Mutex
	coMu sync.Mutex

	// PubSub

	// AllowCreateTopic controls if the transport can create a topic if it does
	// not exist.
	AllowCreateTopic bool

	// AllowCreateSubscription controls if the transport can create a
	// subscription if it does not exist.
	AllowCreateSubscription bool

	projectID      string
	topicID        string
	subscriptionID string

	gccMux sync.Mutex

	subscriptions []subscriptionWithTopic
	client        *pubsub.Client

	connectionsBySubscription map[string]*internal.Connection
	connectionsByTopic        map[string]*internal.Connection

	// Receiver
	Receiver transport.Receiver

	// Converter is invoked if the incoming transport receives an undecodable
	// message.
	Converter transport.Converter
}

// New creates a new pubsub transport.
func New(ctx context.Context, opts ...Option) (*Transport, error) {
	t := &Transport{}
	if err := t.applyOptions(opts...); err != nil {
		return nil, err
	}

	if t.client == nil {
		// Auth to pubsub.
		client, err := pubsub.NewClient(ctx, t.projectID)
		if err != nil {
			return nil, err
		}
		// Success.
		t.client = client
	}

	if t.connectionsBySubscription == nil {
		t.connectionsBySubscription = make(map[string]*internal.Connection, 0)
	}

	if t.connectionsByTopic == nil {
		t.connectionsByTopic = make(map[string]*internal.Connection, 0)
	}
	return t, nil
}

func (t *Transport) applyOptions(opts ...Option) error {
	for _, fn := range opts {
		if err := fn(t); err != nil {
			return err
		}
	}
	return nil
}

func (t *Transport) loadCodec(ctx context.Context) bool {
	if t.codec == nil {
		t.coMu.Lock()
		if t.DefaultEncodingSelectionFn != nil && t.Encoding != Default {
			logger := cecontext.LoggerFrom(ctx)
			logger.Warn("transport has a DefaultEncodingSelectionFn set but Encoding is not Default. DefaultEncodingSelectionFn will be ignored.")

			t.codec = &Codec{
				Encoding: t.Encoding,
			}
		} else {
			t.codec = &Codec{
				Encoding:                   t.Encoding,
				DefaultEncodingSelectionFn: t.DefaultEncodingSelectionFn,
			}
		}
		t.coMu.Unlock()
	}
	return true
}

func (t *Transport) getConnection(ctx context.Context, topic, subscription string) *internal.Connection {
	if subscription != "" {
		if conn, ok := t.connectionsBySubscription[subscription]; ok {
			return conn
		}
	}
	if topic != "" {
		if conn, ok := t.connectionsByTopic[topic]; ok {
			return conn
		}
	}

	return nil
}

func (t *Transport) getOrCreateConnection(ctx context.Context, topic, subscription string) *internal.Connection {
	t.gccMux.Lock()
	defer t.gccMux.Unlock()

	// Get.
	if conn := t.getConnection(ctx, topic, subscription); conn != nil {
		return conn
	}
	// Create.
	conn := &internal.Connection{
		AllowCreateSubscription: t.AllowCreateSubscription,
		AllowCreateTopic:        t.AllowCreateTopic,
		Client:                  t.client,
		ProjectID:               t.projectID,
		TopicID:                 topic,
		SubscriptionID:          subscription,
	}
	// Save for later.
	if subscription != "" {
		t.connectionsBySubscription[subscription] = conn
	}
	if topic != "" {
		t.connectionsByTopic[topic] = conn
	}

	return conn
}

// Send implements Transport.Send
func (t *Transport) Send(ctx context.Context, event cloudevents.Event) (context.Context, *cloudevents.Event, error) {
	// TODO populate response context properly.
	if ok := t.loadCodec(ctx); !ok {
		return ctx, nil, fmt.Errorf("unknown encoding set on transport: %d", t.Encoding)
	}

	topic := cecontext.TopicFrom(ctx)
	if topic == "" {
		topic = t.topicID
	}

	conn := t.getOrCreateConnection(ctx, topic, "")

	msg, err := t.codec.Encode(ctx, event)
	if err != nil {
		return ctx, nil, err
	}

	if m, ok := msg.(*Message); ok {
		respEvent, err := conn.Publish(ctx, &pubsub.Message{
			Attributes: m.Attributes,
			Data:       m.Data,
		})
		return ctx, respEvent, err
	}

	return ctx, nil, fmt.Errorf("failed to encode Event into a Message")
}

// SetReceiver implements Transport.SetReceiver
func (t *Transport) SetReceiver(r transport.Receiver) {
	t.Receiver = r
}

// SetConverter implements Transport.SetConverter
func (t *Transport) SetConverter(c transport.Converter) {
	t.Converter = c
}

// HasConverter implements Transport.HasConverter
func (t *Transport) HasConverter() bool {
	return t.Converter != nil
}

func (t *Transport) startSubscriber(ctx context.Context, sub subscriptionWithTopic, done func(error)) {
	logger := cecontext.LoggerFrom(ctx)
	logger.Infof("starting subscriber for Topic %q, Subscription %q", sub.topicID, sub.subscriptionID)
	conn := t.getOrCreateConnection(ctx, sub.topicID, sub.subscriptionID)

	logger.Info("conn is", conn)
	if conn == nil {
		err := fmt.Errorf("failed to find connection for Topic: %q, Subscription: %q", sub.topicID, sub.subscriptionID)
		done(err)
		return
	}
	// Ok, ready to start pulling.
	err := conn.Receive(ctx, func(ctx context.Context, m *pubsub.Message) {
		msg := &Message{
			Attributes: m.Attributes,
			Data:       m.Data,
		}
		event, err := t.codec.Decode(ctx, msg)
		// If codec returns and error, try with the converter if it is set.
		if err != nil && t.HasConverter() {
			event, err = t.Converter.Convert(ctx, msg, err)
		}
		if err != nil {
			logger.Errorw("failed to decode message", zap.Error(err))
			m.Nack()
			return
		}

		if err := t.Receiver.Receive(ctx, *event, nil); err != nil {
			logger.Warnw("pubsub receiver return err", zap.Error(err))
			m.Nack()
			return
		}
		m.Ack()
	})
	done(err)
}

// StartReceiver implements Transport.StartReceiver
// NOTE: This is a blocking call.
func (t *Transport) StartReceiver(ctx context.Context) error {
	// Load the codec.
	if ok := t.loadCodec(ctx); !ok {
		return fmt.Errorf("unknown encoding set on transport: %d", t.Encoding)
	}

	cctx, cancel := context.WithCancel(ctx)
	defer cancel()
	n := len(t.subscriptions)

	// Make the channels for quit and errors.
	quit := make(chan struct{}, n)
	errc := make(chan error, n)

	// Start up each subscription.
	for _, sub := range t.subscriptions {
		go t.startSubscriber(cctx, sub, func(err error) {
			if err != nil {
				errc <- err
			} else {
				quit <- struct{}{}
			}
		})
	}

	// Collect errors and done calls until we have n of them.
	errs := []string(nil)
	for success := 0; success < n; success++ {
		var err error
		select {
		case <-ctx.Done(): // Block for parent context to finish.
			success--
		case err = <-errc: // Collect errors
		case <-quit:
		}
		if cancel != nil {
			// Stop all other subscriptions.
			cancel()
			cancel = nil
		}
		if err != nil {
			errs = append(errs, err.Error())
		}
	}

	close(quit)
	close(errc)

	return errors.New(strings.Join(errs, "\n"))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"

	"github.com/spf13/cobra"
	"gopkg.in/yaml.v2"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/shared/api"
)

func (c *cmdInit) RunPreseed(cmd *cobra.Command, args []string, d lxd.InstanceServer) (*api.InitPreseed, error) {
	// Read the YAML
	bytes, err := io.ReadAll(os.Stdin)
	if err != nil {
		return nil, fmt.Errorf("Failed to read from stdin: %w", err)
	}

	// Parse the YAML
	config := api.InitPreseed{}
	err = yaml.Unmarshal(bytes, &config)
	if err != nil {
		return nil, fmt.Errorf("Failed to parse the preseed: %w", err)
	}

	return &config, nil
}
<commit_msg>lxd/init: Use strict checking for preseed<commit_after>package main

import (
	"fmt"
	"io"
	"os"

	"github.com/spf13/cobra"
	"gopkg.in/yaml.v2"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/shared/api"
)

func (c *cmdInit) RunPreseed(cmd *cobra.Command, args []string, d lxd.InstanceServer) (*api.InitPreseed, error) {
	// Read the YAML
	bytes, err := io.ReadAll(os.Stdin)
	if err != nil {
		return nil, fmt.Errorf("Failed to read from stdin: %w", err)
	}

	// Parse the YAML
	config := api.InitPreseed{}
	// Use strict checking to notify about unknown keys.
	err = yaml.UnmarshalStrict(bytes, &config)
	if err != nil {
		return nil, fmt.Errorf("Failed to parse the preseed: %w", err)
	}

	return &config, nil
}
<|endoftext|>


<commit_before>package video

import "github.com/32bitkid/bitreader"
import "errors"

// StartCode is a 32 bit code that acts as a marker in a coded bitstream.
// They usually signal the structure of following bits and/or how the bits
// should be interpreted.
//
// Start codes always begin with the 24 bit integer 0x000001 followed by a
// specific identifier.
type StartCode uint32

const (
	StartCodePrefix = 0x000001

	PictureStartCode StartCode = (StartCodePrefix << 8) | 0x00

	// slice_start_code 01 through AF
	MinSliceStartCode StartCode = (StartCodePrefix << 8) | 0x01
	MaxSliceStartCode StartCode = (StartCodePrefix << 8) | 0xAF

	UserDataStartCode       StartCode = (StartCodePrefix << 8) | 0xB2
	SequenceHeaderStartCode StartCode = (StartCodePrefix << 8) | 0xB3
	ExtensionStartCode      StartCode = (StartCodePrefix << 8) | 0xB5
	SequenceEndStartCode    StartCode = (StartCodePrefix << 8) | 0xB7
	GroupStartCode          StartCode = (StartCodePrefix << 8) | 0xB8
)

// ErrUnexpectedStartCode indicates that a start code was read from the bitstream that was unexpected.
var ErrUnexpectedStartCode = errors.New("unexpected start code")

// IsSlice() returns true if the StartCode falls within the
// acceptable range of codes designated as slice start codes.
func (code StartCode) IsSlice() bool {
	return code >= MinSliceStartCode && code <= MaxSliceStartCode
}

// Check() will return true if the next bits in the bitstream match the expected code.
func (expected StartCode) Check(br bitreader.BitReader) (bool, error) {
	if nextbits, err := br.Peek32(32); err != nil {
		return false, err
	} else {
		return StartCode(nextbits) == expected, nil
	}
}

// Assert() returns an error if the next bits in the bitstream do not match the expected code.
func (expected StartCode) Assert(br bitreader.BitReader) error {
	if test, err := expected.Check(br); err != nil {
		return err
	} else if test != true {
		return ErrUnexpectedStartCode
	}
	if err := br.Trash(32); err != nil {
		return err
	}
	return nil
}
<commit_msg>updating documentation<commit_after>package video

import "github.com/32bitkid/bitreader"
import "errors"

// StartCode is a 32 bit code that acts as a marker in a coded bitstream.
// They usually signal the structure of following bits and/or how the bits
// should be interpreted.
//
// Start codes always begin with the 24 bit integer 0x000001 followed by a
// specific identifier.
type StartCode uint32

const (
	StartCodePrefix = 0x000001

	PictureStartCode StartCode = (StartCodePrefix << 8) | 0x00

	// slice_start_code 01 through AF
	MinSliceStartCode StartCode = (StartCodePrefix << 8) | 0x01
	MaxSliceStartCode StartCode = (StartCodePrefix << 8) | 0xAF

	UserDataStartCode       StartCode = (StartCodePrefix << 8) | 0xB2
	SequenceHeaderStartCode StartCode = (StartCodePrefix << 8) | 0xB3
	ExtensionStartCode      StartCode = (StartCodePrefix << 8) | 0xB5
	SequenceEndStartCode    StartCode = (StartCodePrefix << 8) | 0xB7
	GroupStartCode          StartCode = (StartCodePrefix << 8) | 0xB8
)

// ErrUnexpectedStartCode indicates that a start code was read from the bitstream that was unexpected.
var ErrUnexpectedStartCode = errors.New("unexpected start code")

// IsSlice() returns true if the StartCode falls within the
// acceptable range of codes designated as slice start codes.
func (code StartCode) IsSlice() bool {
	return code >= MinSliceStartCode && code <= MaxSliceStartCode
}

// Check() will return true if the next bits in the bitstream match the expected code.
// Check() does not consume any bits from the bitstream and will only return
// an error if there is a underlying error attempting to peek into the bitstream.
func (expected StartCode) Check(br bitreader.BitReader) (bool, error) {
	if nextbits, err := br.Peek32(32); err != nil {
		return false, err
	} else {
		return StartCode(nextbits) == expected, nil
	}
}

// Assert() returns an ErrUnexpectedStartCode if the next bits in the bitstream do not match the expected code.
// If the expected code is present, the the bits are consumed from the bitstream.
func (expected StartCode) Assert(br bitreader.BitReader) error {
	if test, err := expected.Check(br); err != nil {
		return err
	} else if test != true {
		return ErrUnexpectedStartCode
	}
	if err := br.Trash(32); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package zfs

// #include <stdlib.h>
// #include <libzfs.h>
// #include "common.h"
// #include "zpool.h"
// #include "zfs.h"
// #include <memory.h>
// #include <string.h>
import "C"
import (
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

type SendFlags struct {
	Verbose    bool // -v
	Replicate  bool // -R
	DoAll      bool // -I
	FromOrigin bool // -o
	Dedup      bool // -D
	Props      bool // -p
	DryRun     bool // -n
	Parsable   bool // -P
	LargeBlock bool // -L
	EmbedData  bool // -e
	Compress   bool // -c
	Progress   bool
}

type RecvFlags struct {
	Verbose     bool // -v
	IsPrefix    bool // -d
	IsTail      bool // -e
	DryRun      bool // -n
	Force       bool // -r
	Resumable   bool // -s
	NoMount     bool // -u
	CanmountOff bool
	ByteSwap    bool
}

func to_boolean_t(a bool) C.boolean_t {
	if a {
		return 1
	}
	return 0
}

func to_sendflags_t(flags *SendFlags) (cflags *C.sendflags_t) {
	cflags = C.alloc_sendflags()
	// cflags.verbose = to_boolean_t(flags.Verbose)
	cflags.replicate = to_boolean_t(flags.Replicate)
	cflags.doall = to_boolean_t(flags.DoAll)
	cflags.fromorigin = to_boolean_t(flags.FromOrigin)
	cflags.dedup = to_boolean_t(flags.Dedup)
	cflags.props = to_boolean_t(flags.Props)
	cflags.dryrun = to_boolean_t(flags.DryRun)
	cflags.parsable = to_boolean_t(flags.Parsable)
	cflags.progress = to_boolean_t(flags.Progress)
	cflags.largeblock = to_boolean_t(flags.LargeBlock)
	cflags.embed_data = to_boolean_t(flags.EmbedData)
	cflags.compress = to_boolean_t(flags.Compress)
	return
}

func to_recvflags_t(flags *RecvFlags) (cflags *C.recvflags_t) {
	cflags = C.alloc_recvflags()
	cflags.verbose = to_boolean_t(flags.Verbose)
	cflags.isprefix = to_boolean_t(flags.IsPrefix)
	cflags.istail = to_boolean_t(flags.IsTail)
	cflags.dryrun = to_boolean_t(flags.DryRun)
	cflags.force = to_boolean_t(flags.Force)
	cflags.canmountoff = to_boolean_t(flags.CanmountOff)
	// cflags.resumable = to_boolean_t(flags.Resumable)
	cflags.byteswap = to_boolean_t(flags.ByteSwap)
	cflags.nomount = to_boolean_t(flags.NoMount)
	return
}

func (d *Dataset) send(FromName string, outf *os.File, flags *SendFlags) (err error) {
	var cfromname, ctoname *C.char
	var dpath string
	var pd Dataset

	if d.Type != DatasetTypeSnapshot || (len(FromName) > 0 && strings.Contains(FromName, "#")) {
		err = fmt.Errorf(
			"Unsupported method on filesystem or bookmark. Use func SendOne() for that purpose.")
		return
	}

	cflags := to_sendflags_t(flags)
	defer C.free(unsafe.Pointer(cflags))
	if dpath, err = d.Path(); err != nil {
		return
	}
	sendparams := strings.Split(dpath, "@")
	parent := sendparams[0]
	if len(FromName) > 0 {
		if FromName[0] == '@' {
			FromName = FromName[1:]
		} else if strings.Contains(FromName, "/") {
			from := strings.Split(FromName, "@")
			if len(from) > 0 {
				FromName = from[1]
			}
		}
		cfromname = C.CString(FromName)
		defer C.free(unsafe.Pointer(cfromname))
	}
	ctoname = C.CString(sendparams[1])
	defer C.free(unsafe.Pointer(ctoname))
	if pd, err = DatasetOpen(parent); err != nil {
		return
	}
	defer pd.Close()
	cerr := C.zfs_send(pd.list.zh, cfromname, ctoname, cflags, C.int(outf.Fd()), nil, nil, nil)
	if cerr != 0 {
		err = LastError()
	}
	return
}

func (d *Dataset) SendResume(outf *os.File, flags *SendFlags, receiveResumeToken string) (err error) {
	if d.Type != DatasetTypeSnapshot {
		err = fmt.Errorf("Unsupported method on filesystem or bookmark. Use func SendOne() for that purpose.")
		return
	}

	var dpath string
	var pd Dataset

	cflags := to_sendflags_t(flags)
	defer C.free(unsafe.Pointer(cflags))
	if dpath, err = d.Path(); err != nil {
		return
	}
	sendparams := strings.Split(dpath, "@")
	parent := sendparams[0]

	if pd, err = DatasetOpen(parent); err != nil {
		return
	}
	defer pd.Close()

	cReceiveResumeToken := C.CString(receiveResumeToken)
	defer C.free(unsafe.Pointer(cReceiveResumeToken))

	clerr := C.zfs_send_resume(C.libzfsHandle, cflags, C.int(outf.Fd()), cReceiveResumeToken)
	if clerr != 0 {
		err = LastError()
	}

	return
}

func (d *Dataset) SendResume(outf *os.File, flags *SendFlags, receiveResumeToken string) (err error) {
	if d.Type != DatasetTypeSnapshot {
		err = fmt.Errorf("Unsupported method on filesystem or bookmark. Use func SendOne() for that purpose.")
		return
	}

	var dpath string
	var pd Dataset

	cflags := to_sendflags_t(flags)
	defer C.free(unsafe.Pointer(cflags))
	if dpath, err = d.Path(); err != nil {
		return
	}
	sendparams := strings.Split(dpath, "@")
	parent := sendparams[0]

	if pd, err = DatasetOpen(parent); err != nil {
		return
	}
	defer pd.Close()

	cReceiveResumeToken := C.CString(receiveResumeToken)
	defer C.free(unsafe.Pointer(cReceiveResumeToken))

	clerr := C.zfs_send_resume(C.libzfsHandle, cflags, C.int(outf.Fd()), cReceiveResumeToken)
	if clerr != 0 {
		err = LastError()
	}

	return
}

func (d *Dataset) Send(outf *os.File, flags SendFlags) (err error) {
	if flags.Replicate {
		flags.DoAll = true
	}
	err = d.send("", outf, &flags)
	return
}

func (d *Dataset) SendFrom(FromName string, outf *os.File, flags SendFlags) (err error) {
	var porigin Property
	var from, dest []string
	if err = d.ReloadProperties(); err != nil {
		return
	}
	porigin, _ = d.GetProperty(DatasetPropOrigin)
	if len(porigin.Value) > 0 && porigin.Value == FromName {
		FromName = ""
		flags.FromOrigin = true
	} else {
		var dpath string
		if dpath, err = d.Path(); err != nil {
			return
		}
		dest = strings.Split(dpath, "@")
		from = strings.Split(FromName, "@")

		if len(from[0]) > 0 && from[0] != dest[0] {
			err = fmt.Errorf("Incremental source must be in same filesystem.")
			return
		}
		if len(from) < 2 || strings.Contains(from[1], "@") || strings.Contains(from[1], "/") {
			err = fmt.Errorf("Invalid incremental source.")
			return
		}
	}
	err = d.send("@"+from[1], outf, &flags)
	return
}

// SendSize - estimate snapshot size to transfer
func (d *Dataset) SendSize(FromName string, flags SendFlags) (size int64, err error) {
	var r, w *os.File
	errch := make(chan error)
	defer func() {
		select {
		case <-errch:
		default:
		}
		close(errch)
	}()
	flags.DryRun = true
	flags.Verbose = true
	flags.Progress = true
	flags.Parsable = true
	if r, w, err = os.Pipe(); err != nil {
		return
	}
	defer r.Close()
	go func() {
		var tmpe error
		saveOut := C.redirect_libzfs_stdout(C.int(w.Fd()))
		if saveOut < 0 {
			tmpe = fmt.Errorf("Redirection of zfslib stdout failed %d", saveOut)
		} else {
			tmpe = d.send(FromName, w, &flags)
			C.restore_libzfs_stdout(saveOut)
		}
		w.Close()
		errch <- tmpe
	}()

	r.SetReadDeadline(time.Now().Add(60 * time.Second))
	var data []byte
	if data, err = ioutil.ReadAll(r); err != nil {
		return
	}
	// parse size
	var sizeRe *regexp.Regexp
	if sizeRe, err = regexp.Compile("size[ \t]*([0-9]+)"); err != nil {
		return
	}
	matches := sizeRe.FindAllSubmatch(data, 3)
	if len(matches) > 0 && len(matches[0]) > 1 {
		if size, err = strconv.ParseInt(
			string(matches[0][1]), 10, 64); err != nil {
			return
		}
	}
	err = <-errch
	return
}

// Receive - receive snapshot stream
func (d *Dataset) Receive(inf *os.File, flags RecvFlags) (err error) {
	var dpath string
	if dpath, err = d.Path(); err != nil {
		return
	}
	props := C.new_property_nvlist()
	if props == nil {
		err = fmt.Errorf("Out of memory func (d *Dataset) Recv()")
		return
	}
	defer C.nvlist_free(props)
	cflags := to_recvflags_t(&flags)
	defer C.free(unsafe.Pointer(cflags))
	dest := C.CString(dpath)
	defer C.free(unsafe.Pointer(dest))
	ec := C.zfs_receive(C.libzfsHandle, dest, nil, cflags, C.int(inf.Fd()), nil)
	if ec != 0 {
		err = fmt.Errorf("ZFS receive of %s failed. %s", C.GoString(dest), LastError().Error())
	}
	return
}
<commit_msg>Remove SendOne since it does not make sense in context of this lib<commit_after>package zfs

// #include <stdlib.h>
// #include <libzfs.h>
// #include "common.h"
// #include "zpool.h"
// #include "zfs.h"
// #include <memory.h>
// #include <string.h>
import "C"
import (
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

type SendFlags struct {
	Verbose    bool // -v
	Replicate  bool // -R
	DoAll      bool // -I
	FromOrigin bool // -o
	Dedup      bool // -D
	Props      bool // -p
	DryRun     bool // -n
	Parsable   bool // -P
	LargeBlock bool // -L
	EmbedData  bool // -e
	Compress   bool // -c
	Progress   bool
}

type RecvFlags struct {
	Verbose     bool // -v
	IsPrefix    bool // -d
	IsTail      bool // -e
	DryRun      bool // -n
	Force       bool // -r
	Resumable   bool // -s
	NoMount     bool // -u
	CanmountOff bool
	ByteSwap    bool
}

func to_boolean_t(a bool) C.boolean_t {
	if a {
		return 1
	}
	return 0
}

func to_sendflags_t(flags *SendFlags) (cflags *C.sendflags_t) {
	cflags = C.alloc_sendflags()
	// cflags.verbose = to_boolean_t(flags.Verbose)
	cflags.replicate = to_boolean_t(flags.Replicate)
	cflags.doall = to_boolean_t(flags.DoAll)
	cflags.fromorigin = to_boolean_t(flags.FromOrigin)
	cflags.dedup = to_boolean_t(flags.Dedup)
	cflags.props = to_boolean_t(flags.Props)
	cflags.dryrun = to_boolean_t(flags.DryRun)
	cflags.parsable = to_boolean_t(flags.Parsable)
	cflags.progress = to_boolean_t(flags.Progress)
	cflags.largeblock = to_boolean_t(flags.LargeBlock)
	cflags.embed_data = to_boolean_t(flags.EmbedData)
	cflags.compress = to_boolean_t(flags.Compress)
	return
}

func to_recvflags_t(flags *RecvFlags) (cflags *C.recvflags_t) {
	cflags = C.alloc_recvflags()
	cflags.verbose = to_boolean_t(flags.Verbose)
	cflags.isprefix = to_boolean_t(flags.IsPrefix)
	cflags.istail = to_boolean_t(flags.IsTail)
	cflags.dryrun = to_boolean_t(flags.DryRun)
	cflags.force = to_boolean_t(flags.Force)
	cflags.canmountoff = to_boolean_t(flags.CanmountOff)
	// cflags.resumable = to_boolean_t(flags.Resumable)
	cflags.byteswap = to_boolean_t(flags.ByteSwap)
	cflags.nomount = to_boolean_t(flags.NoMount)
	return
}

func (d *Dataset) send(FromName string, outf *os.File, flags *SendFlags) (err error) {
	var cfromname, ctoname *C.char
	var dpath string
	var pd Dataset

	if d.Type != DatasetTypeSnapshot || (len(FromName) > 0 && strings.Contains(FromName, "#")) {
		err = fmt.Errorf(
			"Unsupported method on filesystem or bookmark. Use func SendOne() for that purpose.")
		return
	}

	cflags := to_sendflags_t(flags)
	defer C.free(unsafe.Pointer(cflags))
	if dpath, err = d.Path(); err != nil {
		return
	}
	sendparams := strings.Split(dpath, "@")
	parent := sendparams[0]
	if len(FromName) > 0 {
		if FromName[0] == '@' {
			FromName = FromName[1:]
		} else if strings.Contains(FromName, "/") {
			from := strings.Split(FromName, "@")
			if len(from) > 0 {
				FromName = from[1]
			}
		}
		cfromname = C.CString(FromName)
		defer C.free(unsafe.Pointer(cfromname))
	}
	ctoname = C.CString(sendparams[1])
	defer C.free(unsafe.Pointer(ctoname))
	if pd, err = DatasetOpen(parent); err != nil {
		return
	}
	defer pd.Close()
	cerr := C.zfs_send(pd.list.zh, cfromname, ctoname, cflags, C.int(outf.Fd()), nil, nil, nil)
	if cerr != 0 {
		err = LastError()
	}
	return
}

func (d *Dataset) SendResume(outf *os.File, flags *SendFlags, receiveResumeToken string) (err error) {
	if d.Type != DatasetTypeSnapshot {
		err = fmt.Errorf("Unsupported method on filesystem or bookmark. Use func SendOne() for that purpose.")
		return
	}

	var dpath string
	var pd Dataset

	cflags := to_sendflags_t(flags)
	defer C.free(unsafe.Pointer(cflags))
	if dpath, err = d.Path(); err != nil {
		return
	}
	sendparams := strings.Split(dpath, "@")
	parent := sendparams[0]

	if pd, err = DatasetOpen(parent); err != nil {
		return
	}
	defer pd.Close()

	cReceiveResumeToken := C.CString(receiveResumeToken)
	defer C.free(unsafe.Pointer(cReceiveResumeToken))

	clerr := C.zfs_send_resume(C.libzfsHandle, cflags, C.int(outf.Fd()), cReceiveResumeToken)
	if clerr != 0 {
		err = LastError()
	}

	return
}

func (d *Dataset) Send(outf *os.File, flags SendFlags) (err error) {
	if flags.Replicate {
		flags.DoAll = true
	}
	err = d.send("", outf, &flags)
	return
}

func (d *Dataset) SendFrom(FromName string, outf *os.File, flags SendFlags) (err error) {
	var porigin Property
	var from, dest []string
	if err = d.ReloadProperties(); err != nil {
		return
	}
	porigin, _ = d.GetProperty(DatasetPropOrigin)
	if len(porigin.Value) > 0 && porigin.Value == FromName {
		FromName = ""
		flags.FromOrigin = true
	} else {
		var dpath string
		if dpath, err = d.Path(); err != nil {
			return
		}
		dest = strings.Split(dpath, "@")
		from = strings.Split(FromName, "@")

		if len(from[0]) > 0 && from[0] != dest[0] {
			err = fmt.Errorf("Incremental source must be in same filesystem.")
			return
		}
		if len(from) < 2 || strings.Contains(from[1], "@") || strings.Contains(from[1], "/") {
			err = fmt.Errorf("Invalid incremental source.")
			return
		}
	}
	err = d.send("@"+from[1], outf, &flags)
	return
}

// SendSize - estimate snapshot size to transfer
func (d *Dataset) SendSize(FromName string, flags SendFlags) (size int64, err error) {
	var r, w *os.File
	errch := make(chan error)
	defer func() {
		select {
		case <-errch:
		default:
		}
		close(errch)
	}()
	flags.DryRun = true
	flags.Verbose = true
	flags.Progress = true
	flags.Parsable = true
	if r, w, err = os.Pipe(); err != nil {
		return
	}
	defer r.Close()
	go func() {
		var tmpe error
		saveOut := C.redirect_libzfs_stdout(C.int(w.Fd()))
		if saveOut < 0 {
			tmpe = fmt.Errorf("Redirection of zfslib stdout failed %d", saveOut)
		} else {
			tmpe = d.send(FromName, w, &flags)
			C.restore_libzfs_stdout(saveOut)
		}
		w.Close()
		errch <- tmpe
	}()

	r.SetReadDeadline(time.Now().Add(60 * time.Second))
	var data []byte
	if data, err = ioutil.ReadAll(r); err != nil {
		return
	}
	// parse size
	var sizeRe *regexp.Regexp
	if sizeRe, err = regexp.Compile("size[ \t]*([0-9]+)"); err != nil {
		return
	}
	matches := sizeRe.FindAllSubmatch(data, 3)
	if len(matches) > 0 && len(matches[0]) > 1 {
		if size, err = strconv.ParseInt(
			string(matches[0][1]), 10, 64); err != nil {
			return
		}
	}
	err = <-errch
	return
}

// Receive - receive snapshot stream
func (d *Dataset) Receive(inf *os.File, flags RecvFlags) (err error) {
	var dpath string
	if dpath, err = d.Path(); err != nil {
		return
	}
	props := C.new_property_nvlist()
	if props == nil {
		err = fmt.Errorf("Out of memory func (d *Dataset) Recv()")
		return
	}
	defer C.nvlist_free(props)
	cflags := to_recvflags_t(&flags)
	defer C.free(unsafe.Pointer(cflags))
	dest := C.CString(dpath)
	defer C.free(unsafe.Pointer(dest))
	ec := C.zfs_receive(C.libzfsHandle, dest, nil, cflags, C.int(inf.Fd()), nil)
	if ec != 0 {
		err = fmt.Errorf("ZFS receive of %s failed. %s", C.GoString(dest), LastError().Error())
	}
	return
}
<|endoftext|>


<commit_before>package zfs

// #include <stdlib.h>
// #include <libzfs.h>
// #include "common.h"
// #include "zpool.h"
// #include "zfs.h"
// #include <memory.h>
// #include <string.h>
import "C"
import (
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

type SendFlags struct {
	Verbose    bool // -v
	Replicate  bool // -R
	DoAll      bool // -I
	FromOrigin bool // -o
	Dedup      bool // -D
	Props      bool // -p
	DryRun     bool // -n
	Parsable   bool // -P
	LargeBlock bool // -L
	EmbedData  bool // -e
	Compress   bool // -c
	Progress   bool
}

type RecvFlags struct {
	Verbose     bool // -v
	IsPrefix    bool // -d
	IsTail      bool // -e
	DryRun      bool // -n
	Force       bool // -r
	Resumable   bool // -s
	NoMount     bool // -u
	CanmountOff bool
	ByteSwap    bool
}

func to_boolean_t(a bool) C.boolean_t {
	if a {
		return 1
	}
	return 0
}

func to_sendflags_t(flags *SendFlags) (cflags *C.sendflags_t) {
	cflags = C.alloc_sendflags()
	// cflags.verbose = to_boolean_t(flags.Verbose)
	cflags.replicate = to_boolean_t(flags.Replicate)
	cflags.doall = to_boolean_t(flags.DoAll)
	cflags.fromorigin = to_boolean_t(flags.FromOrigin)
	cflags.dedup = to_boolean_t(flags.Dedup)
	cflags.props = to_boolean_t(flags.Props)
	cflags.dryrun = to_boolean_t(flags.DryRun)
	cflags.parsable = to_boolean_t(flags.Parsable)
	cflags.progress = to_boolean_t(flags.Progress)
	cflags.largeblock = to_boolean_t(flags.LargeBlock)
	cflags.embed_data = to_boolean_t(flags.EmbedData)
	cflags.compress = to_boolean_t(flags.Compress)
	return
}

func to_recvflags_t(flags *RecvFlags) (cflags *C.recvflags_t) {
	cflags = C.alloc_recvflags()
	cflags.verbose = to_boolean_t(flags.Verbose)
	cflags.isprefix = to_boolean_t(flags.IsPrefix)
	cflags.istail = to_boolean_t(flags.IsTail)
	cflags.dryrun = to_boolean_t(flags.DryRun)
	cflags.force = to_boolean_t(flags.Force)
	cflags.canmountoff = to_boolean_t(flags.CanmountOff)
	// cflags.resumable = to_boolean_t(flags.Resumable)
	cflags.byteswap = to_boolean_t(flags.ByteSwap)
	cflags.nomount = to_boolean_t(flags.NoMount)
	return
}

func (d *Dataset) send(FromName string, outf *os.File, flags *SendFlags) (err error) {
	var cfromname, ctoname *C.char
	var dpath string
	var pd Dataset

	if d.Type != DatasetTypeSnapshot || (len(FromName) > 0 && strings.Contains(FromName, "#")) {
		err = fmt.Errorf(
			"Unsupported method on filesystem or bookmark. Use func SendOne() for that purpose.")
		return
	}

	cflags := to_sendflags_t(flags)
	defer C.free(unsafe.Pointer(cflags))
	if dpath, err = d.Path(); err != nil {
		return
	}
	sendparams := strings.Split(dpath, "@")
	parent := sendparams[0]
	if len(FromName) > 0 {
		if FromName[0] == '@' {
			FromName = FromName[1:]
		} else if strings.Contains(FromName, "/") {
			from := strings.Split(FromName, "@")
			if len(from) > 0 {
				FromName = from[1]
			}
		}
		cfromname = C.CString(FromName)
		defer C.free(unsafe.Pointer(cfromname))
	}
	ctoname = C.CString(sendparams[1])
	defer C.free(unsafe.Pointer(ctoname))
	if pd, err = DatasetOpen(parent); err != nil {
		return
	}
	defer pd.Close()
	cerr := C.zfs_send(pd.list.zh, cfromname, ctoname, cflags, C.int(outf.Fd()), nil, nil, nil)
	if cerr != 0 {
		err = LastError()
	}
	return
}

func (d *Dataset) SendResume(outf *os.File, flags *SendFlags, receiveResumeToken string) (err error) {
	if d.Type != DatasetTypeSnapshot {
		err = fmt.Errorf("Unsupported method on filesystem or bookmark. Use func SendOne() for that purpose.")
		return
	}

	var dpath string
	var pd Dataset

	cflags := to_sendflags_t(flags)
	defer C.free(unsafe.Pointer(cflags))
	if dpath, err = d.Path(); err != nil {
		return
	}
	sendparams := strings.Split(dpath, "@")
	parent := sendparams[0]

	if pd, err = DatasetOpen(parent); err != nil {
		return
	}
	defer pd.Close()

	cReceiveResumeToken := C.CString(receiveResumeToken)
	defer C.free(unsafe.Pointer(cReceiveResumeToken))

	clerr := C.zfs_send_resume(C.libzfsHandle, cflags, C.int(outf.Fd()), cReceiveResumeToken)
	if clerr != 0 {
		err = LastError()
	}

	return
}

func (d *Dataset) Send(outf *os.File, flags SendFlags) (err error) {
	if flags.Replicate {
		flags.DoAll = true
	}
	err = d.send("", outf, &flags)
	return
}

func (d *Dataset) SendFrom(FromName string, outf *os.File, flags SendFlags) (err error) {
	var porigin Property
	var from, dest []string
	if err = d.ReloadProperties(); err != nil {
		return
	}
	porigin, _ = d.GetProperty(DatasetPropOrigin)
	if len(porigin.Value) > 0 && porigin.Value == FromName {
		FromName = ""
		flags.FromOrigin = true
	} else {
		var dpath string
		if dpath, err = d.Path(); err != nil {
			return
		}
		dest = strings.Split(dpath, "@")
		from = strings.Split(FromName, "@")

		if len(from[0]) > 0 && from[0] != dest[0] {
			err = fmt.Errorf("Incremental source must be in same filesystem.")
			return
		}
		if len(from) < 2 || strings.Contains(from[1], "@") || strings.Contains(from[1], "/") {
			err = fmt.Errorf("Invalid incremental source.")
			return
		}
	}
	err = d.send("@"+from[1], outf, &flags)
	return
}

// SendSize - estimate snapshot size to transfer
func (d *Dataset) SendSize(FromName string, flags SendFlags) (size int64, err error) {
	var r, w *os.File
	errch := make(chan error)
	defer func() {
		select {
		case <-errch:
		default:
		}
		close(errch)
	}()
	flags.DryRun = true
	flags.Verbose = true
	flags.Progress = true
	flags.Parsable = true
	if r, w, err = os.Pipe(); err != nil {
		return
	}
	defer r.Close()
	go func() {
		var tmpe error
		saveOut := C.redirect_libzfs_stdout(C.int(w.Fd()))
		if saveOut < 0 {
			tmpe = fmt.Errorf("Redirection of zfslib stdout failed %d", saveOut)
		} else {
			tmpe = d.send(FromName, w, &flags)
			C.restore_libzfs_stdout(saveOut)
		}
		w.Close()
		errch <- tmpe
	}()

	r.SetReadDeadline(time.Now().Add(60 * time.Second))
	var data []byte
	if data, err = ioutil.ReadAll(r); err != nil {
		return
	}
	// parse size
	var sizeRe *regexp.Regexp
	if sizeRe, err = regexp.Compile("size[ \t]*([0-9]+)"); err != nil {
		return
	}
	matches := sizeRe.FindAllSubmatch(data, 3)
	if len(matches) > 0 && len(matches[0]) > 1 {
		if size, err = strconv.ParseInt(
			string(matches[0][1]), 10, 64); err != nil {
			return
		}
	}
	err = <-errch
	return
}

// Receive - receive snapshot stream
func (d *Dataset) Receive(inf *os.File, flags RecvFlags) (err error) {
	var dpath string
	if dpath, err = d.Path(); err != nil {
		return
	}
	props := C.new_property_nvlist()
	if props == nil {
		err = fmt.Errorf("Out of memory func (d *Dataset) Recv()")
		return
	}
	defer C.nvlist_free(props)
	cflags := to_recvflags_t(&flags)
	defer C.free(unsafe.Pointer(cflags))
	dest := C.CString(dpath)
	defer C.free(unsafe.Pointer(dest))
	ec := C.zfs_receive(C.libzfsHandle, dest, nil, cflags, C.int(inf.Fd()), nil)
	if ec != 0 {
		err = fmt.Errorf("ZFS receive of %s failed. %s", C.GoString(dest), LastError().Error())
	}
	return
}
<commit_msg> - Option to resume interrupted send<commit_after>package zfs

// #include <stdlib.h>
// #include <libzfs.h>
// #include "common.h"
// #include "zpool.h"
// #include "zfs.h"
// #include <memory.h>
// #include <string.h>
import "C"
import (
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

type SendFlags struct {
	Verbose    bool // -v
	Replicate  bool // -R
	DoAll      bool // -I
	FromOrigin bool // -o
	Dedup      bool // -D
	Props      bool // -p
	DryRun     bool // -n
	Parsable   bool // -P
	LargeBlock bool // -L
	EmbedData  bool // -e
	Compress   bool // -c
	Progress   bool
}

type RecvFlags struct {
	Verbose     bool // -v
	IsPrefix    bool // -d
	IsTail      bool // -e
	DryRun      bool // -n
	Force       bool // -r
	Resumable   bool // -s
	NoMount     bool // -u
	CanmountOff bool
	ByteSwap    bool
}

func to_boolean_t(a bool) C.boolean_t {
	if a {
		return 1
	}
	return 0
}

func to_sendflags_t(flags *SendFlags) (cflags *C.sendflags_t) {
	cflags = C.alloc_sendflags()
	// cflags.verbose = to_boolean_t(flags.Verbose)
	cflags.replicate = to_boolean_t(flags.Replicate)
	cflags.doall = to_boolean_t(flags.DoAll)
	cflags.fromorigin = to_boolean_t(flags.FromOrigin)
	cflags.dedup = to_boolean_t(flags.Dedup)
	cflags.props = to_boolean_t(flags.Props)
	cflags.dryrun = to_boolean_t(flags.DryRun)
	cflags.parsable = to_boolean_t(flags.Parsable)
	cflags.progress = to_boolean_t(flags.Progress)
	cflags.largeblock = to_boolean_t(flags.LargeBlock)
	cflags.embed_data = to_boolean_t(flags.EmbedData)
	cflags.compress = to_boolean_t(flags.Compress)
	return
}

func to_recvflags_t(flags *RecvFlags) (cflags *C.recvflags_t) {
	cflags = C.alloc_recvflags()
	cflags.verbose = to_boolean_t(flags.Verbose)
	cflags.isprefix = to_boolean_t(flags.IsPrefix)
	cflags.istail = to_boolean_t(flags.IsTail)
	cflags.dryrun = to_boolean_t(flags.DryRun)
	cflags.force = to_boolean_t(flags.Force)
	cflags.canmountoff = to_boolean_t(flags.CanmountOff)
	// cflags.resumable = to_boolean_t(flags.Resumable)
	cflags.byteswap = to_boolean_t(flags.ByteSwap)
	cflags.nomount = to_boolean_t(flags.NoMount)
	return
}

func (d *Dataset) send(FromName string, outf *os.File, flags *SendFlags) (err error) {
	var cfromname, ctoname *C.char
	var dpath string
	var pd Dataset

	if d.Type != DatasetTypeSnapshot || (len(FromName) > 0 && strings.Contains(FromName, "#")) {
		err = fmt.Errorf(
			"Unsupported method on filesystem or bookmark. Use func SendOne() for that purpose.")
		return
	}

	cflags := to_sendflags_t(flags)
	defer C.free(unsafe.Pointer(cflags))
	if dpath, err = d.Path(); err != nil {
		return
	}
	sendparams := strings.Split(dpath, "@")
	parent := sendparams[0]
	if len(FromName) > 0 {
		if FromName[0] == '@' {
			FromName = FromName[1:]
		} else if strings.Contains(FromName, "/") {
			from := strings.Split(FromName, "@")
			if len(from) > 0 {
				FromName = from[1]
			}
		}
		cfromname = C.CString(FromName)
		defer C.free(unsafe.Pointer(cfromname))
	}
	ctoname = C.CString(sendparams[1])
	defer C.free(unsafe.Pointer(ctoname))
	if pd, err = DatasetOpen(parent); err != nil {
		return
	}
	defer pd.Close()
	cerr := C.zfs_send(pd.list.zh, cfromname, ctoname, cflags, C.int(outf.Fd()), nil, nil, nil)
	if cerr != 0 {
		err = LastError()
	}
	return
}

func (d *Dataset) SendResume(outf *os.File, flags *SendFlags, receiveResumeToken string) (err error) {
	if d.Type != DatasetTypeSnapshot {
		err = fmt.Errorf("Unsupported method on filesystem or bookmark. Use func SendOne() for that purpose.")
		return
	}

	var dpath string
	var pd Dataset

	cflags := to_sendflags_t(flags)
	defer C.free(unsafe.Pointer(cflags))
	if dpath, err = d.Path(); err != nil {
		return
	}
	sendparams := strings.Split(dpath, "@")
	parent := sendparams[0]

	if pd, err = DatasetOpen(parent); err != nil {
		return
	}
	defer pd.Close()

	cReceiveResumeToken := C.CString(receiveResumeToken)
	defer C.free(unsafe.Pointer(cReceiveResumeToken))

	clerr := C.zfs_send_resume(C.libzfsHandle, cflags, C.int(outf.Fd()), cReceiveResumeToken)
	if clerr != 0 {
		err = LastError()
	}

	return
}

func (d *Dataset) SendResume(outf *os.File, flags *SendFlags, receiveResumeToken string) (err error) {
	if d.Type != DatasetTypeSnapshot {
		err = fmt.Errorf("Unsupported method on filesystem or bookmark. Use func SendOne() for that purpose.")
		return
	}

	var dpath string
	var pd Dataset

	cflags := to_sendflags_t(flags)
	defer C.free(unsafe.Pointer(cflags))
	if dpath, err = d.Path(); err != nil {
		return
	}
	sendparams := strings.Split(dpath, "@")
	parent := sendparams[0]

	if pd, err = DatasetOpen(parent); err != nil {
		return
	}
	defer pd.Close()

	cReceiveResumeToken := C.CString(receiveResumeToken)
	defer C.free(unsafe.Pointer(cReceiveResumeToken))

	clerr := C.zfs_send_resume(C.libzfsHandle, cflags, C.int(outf.Fd()), cReceiveResumeToken)
	if clerr != 0 {
		err = LastError()
		fmt.Println(err.Error())
	}

	return
}

func (d *Dataset) Send(outf *os.File, flags SendFlags) (err error) {
	if flags.Replicate {
		flags.DoAll = true
	}
	err = d.send("", outf, &flags)
	return
}

func (d *Dataset) SendFrom(FromName string, outf *os.File, flags SendFlags) (err error) {
	var porigin Property
	var from, dest []string
	if err = d.ReloadProperties(); err != nil {
		return
	}
	porigin, _ = d.GetProperty(DatasetPropOrigin)
	if len(porigin.Value) > 0 && porigin.Value == FromName {
		FromName = ""
		flags.FromOrigin = true
	} else {
		var dpath string
		if dpath, err = d.Path(); err != nil {
			return
		}
		dest = strings.Split(dpath, "@")
		from = strings.Split(FromName, "@")

		if len(from[0]) > 0 && from[0] != dest[0] {
			err = fmt.Errorf("Incremental source must be in same filesystem.")
			return
		}
		if len(from) < 2 || strings.Contains(from[1], "@") || strings.Contains(from[1], "/") {
			err = fmt.Errorf("Invalid incremental source.")
			return
		}
	}
	err = d.send("@"+from[1], outf, &flags)
	return
}

// SendSize - estimate snapshot size to transfer
func (d *Dataset) SendSize(FromName string, flags SendFlags) (size int64, err error) {
	var r, w *os.File
	errch := make(chan error)
	defer func() {
		select {
		case <-errch:
		default:
		}
		close(errch)
	}()
	flags.DryRun = true
	flags.Verbose = true
	flags.Progress = true
	flags.Parsable = true
	if r, w, err = os.Pipe(); err != nil {
		return
	}
	defer r.Close()
	go func() {
		var tmpe error
		saveOut := C.redirect_libzfs_stdout(C.int(w.Fd()))
		if saveOut < 0 {
			tmpe = fmt.Errorf("Redirection of zfslib stdout failed %d", saveOut)
		} else {
			tmpe = d.send(FromName, w, &flags)
			C.restore_libzfs_stdout(saveOut)
		}
		w.Close()
		errch <- tmpe
	}()

	r.SetReadDeadline(time.Now().Add(60 * time.Second))
	var data []byte
	if data, err = ioutil.ReadAll(r); err != nil {
		return
	}
	// parse size
	var sizeRe *regexp.Regexp
	if sizeRe, err = regexp.Compile("size[ \t]*([0-9]+)"); err != nil {
		return
	}
	matches := sizeRe.FindAllSubmatch(data, 3)
	if len(matches) > 0 && len(matches[0]) > 1 {
		if size, err = strconv.ParseInt(
			string(matches[0][1]), 10, 64); err != nil {
			return
		}
	}
	err = <-errch
	return
}

// Receive - receive snapshot stream
func (d *Dataset) Receive(inf *os.File, flags RecvFlags) (err error) {
	var dpath string
	if dpath, err = d.Path(); err != nil {
		return
	}
	props := C.new_property_nvlist()
	if props == nil {
		err = fmt.Errorf("Out of memory func (d *Dataset) Recv()")
		return
	}
	defer C.nvlist_free(props)
	cflags := to_recvflags_t(&flags)
	defer C.free(unsafe.Pointer(cflags))
	dest := C.CString(dpath)
	defer C.free(unsafe.Pointer(dest))
	ec := C.zfs_receive(C.libzfsHandle, dest, nil, cflags, C.int(inf.Fd()), nil)
	if ec != 0 {
		err = fmt.Errorf("ZFS receive of %s failed. %s", C.GoString(dest), LastError().Error())
	}
	return
}
<|endoftext|>


<commit_before>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 - 2019 Weaviate. All rights reserved.
 * LICENSE: https://github.com/creativesoftwarefdn/weaviate/blob/develop/LICENSE.md
 * DESIGN & CONCEPT: Bob van Luijt (@bobvanluijt)
 * CONTACT: hello@creativesoftwarefdn.org
 */package batch

import (
	"fmt"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/creativesoftwarefdn/weaviate/database/schema/crossref"
	"github.com/creativesoftwarefdn/weaviate/models"
	batchmodels "github.com/creativesoftwarefdn/weaviate/restapi/batch/models"
	"github.com/creativesoftwarefdn/weaviate/restapi/operations"
	rest_api_utils "github.com/creativesoftwarefdn/weaviate/restapi/rest_api_utils"
	"github.com/creativesoftwarefdn/weaviate/restapi/state"
	"github.com/creativesoftwarefdn/weaviate/telemetry"
	middleware "github.com/go-openapi/runtime/middleware"
)

type referencesRequest struct {
	*http.Request
	*state.State
	locks *rest_api_utils.RequestLocks
	log   *telemetry.RequestsLog
}

// References adds cross-references between classes in batch
func (b *Batch) References(params operations.WeaviateBatchingReferencesCreateParams, principal *models.Principal) middleware.Responder {
	defer b.appState.Messaging.TimeTrack(time.Now())

	r := newReferencesRequest(params.HTTPRequest, b.appState)
	if errResponder := r.lock(); errResponder != nil {
		return errResponder
	}
	defer r.unlock()

	if errResponder := r.validateForm(params); errResponder != nil {
		return errResponder
	}

	batchReferences := r.validateConcurrently(params.Body)
	if err := r.locks.DBConnector.AddBatchReferences(r.Context(), batchReferences); err != nil {
		return operations.NewWeaviateBatchingReferencesCreateInternalServerError().
			WithPayload(errPayloadFromSingleErr(err))
	}

	return operations.NewWeaviateBatchingReferencesCreateOK().
		WithPayload(batchReferences.Response())
}

func newReferencesRequest(r *http.Request, deps *state.State, log *telemetry.RequestsLog) *referencesRequest {
	return &referencesRequest{
		Request: r,
		State:   deps,
		log:     log,
	}
}

// a call to lock() should always be followed by a deferred call to unlock()
func (r *referencesRequest) lock() middleware.Responder {
	dbLock, err := r.Database.ConnectorLock()
	if err != nil {
		return operations.NewWeaviateBatchingReferencesCreateUnprocessableEntity().WithPayload(errPayloadFromSingleErr(err))
	}
	r.locks = &rest_api_utils.RequestLocks{
		DBLock:      dbLock,
		DBConnector: dbLock.Connector(),
	}

	return nil
}

func (r *referencesRequest) unlock() {
	r.locks.DBLock.Unlock()
}

func (r *referencesRequest) validateForm(params operations.WeaviateBatchingReferencesCreateParams) middleware.Responder {
	if len(params.Body) == 0 {
		err := fmt.Errorf("length cannot be 0, need at least one reference for batching")
		return operations.NewWeaviateBatchingReferencesCreateUnprocessableEntity().WithPayload(errPayloadFromSingleErr(err))
	}

	return nil
}

func (r *referencesRequest) validateConcurrently(refs []*models.BatchReference) batchmodels.References {
	c := make(chan batchmodels.Reference, len(refs))
	wg := new(sync.WaitGroup)

	// Generate a goroutine for each separate request
	for i, ref := range refs {
		wg.Add(1)
		go r.validateReference(wg, ref, i, &c)
	}

	wg.Wait()
	close(c)
	return referencesChanToSlice(c)
}

func (r *referencesRequest) validateReference(wg *sync.WaitGroup, ref *models.BatchReference,
	i int, resultsC *chan batchmodels.Reference) {
	defer wg.Done()
	var errors []error
	source, err := crossref.ParseSource(string(ref.From))
	if err != nil {
		errors = append(errors, err)
	} else if !source.Local {
		errors = append(errors, fmt.Errorf("source class must always point to the local peer, but got %s",
			source.PeerName))
	}

	target, err := crossref.Parse(string(ref.To))
	if err != nil {
		errors = append(errors, err)
	} else if !target.Local {
		errors = append(errors, fmt.Errorf("importing network references in batch is not possible. "+
			"Please perform a regular non-batch import for network references, got peer %s",
			target.PeerName))
	}

	if len(errors) == 0 {
		err = nil
	} else {
		err = joinErrors(errors)
	}

	if err == nil {
		// Register the request
		go func() {
			r.log.Register(telemetry.TypeREST, telemetry.LocalManipulate)
		}()
	}

	*resultsC <- batchmodels.Reference{
		From:          source,
		To:            target,
		Err:           err,
		OriginalIndex: i,
	}
}

func referencesChanToSlice(c chan batchmodels.Reference) batchmodels.References {
	result := make([]batchmodels.Reference, len(c), len(c))
	for reference := range c {
		result[reference.OriginalIndex] = reference
	}

	return result
}

func joinErrors(errors []error) error {
	errorStrings := []string{}
	for _, err := range errors {
		if err != nil {
			errorStrings = append(errorStrings, err.Error())
		}
	}

	if len(errorStrings) == 0 {
		return nil
	}

	return fmt.Errorf(strings.Join(errorStrings, ", "))
}
<commit_msg>gh-699: bugfixes<commit_after>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 - 2019 Weaviate. All rights reserved.
 * LICENSE: https://github.com/creativesoftwarefdn/weaviate/blob/develop/LICENSE.md
 * DESIGN & CONCEPT: Bob van Luijt (@bobvanluijt)
 * CONTACT: hello@creativesoftwarefdn.org
 */package batch

import (
	"fmt"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/creativesoftwarefdn/weaviate/database/schema/crossref"
	"github.com/creativesoftwarefdn/weaviate/models"
	batchmodels "github.com/creativesoftwarefdn/weaviate/restapi/batch/models"
	"github.com/creativesoftwarefdn/weaviate/restapi/operations"
	rest_api_utils "github.com/creativesoftwarefdn/weaviate/restapi/rest_api_utils"
	"github.com/creativesoftwarefdn/weaviate/restapi/state"
	"github.com/creativesoftwarefdn/weaviate/telemetry"
	middleware "github.com/go-openapi/runtime/middleware"
)

type referencesRequest struct {
	*http.Request
	*state.State
	locks *rest_api_utils.RequestLocks
	log   *telemetry.RequestsLog
}

// References adds cross-references between classes in batch
func (b *Batch) References(params operations.WeaviateBatchingReferencesCreateParams, principal *models.Principal) middleware.Responder {
	defer b.appState.Messaging.TimeTrack(time.Now())

	r := newReferencesRequest(params.HTTPRequest, b.appState, b.requestsLog)
	if errResponder := r.lock(); errResponder != nil {
		return errResponder
	}
	defer r.unlock()

	if errResponder := r.validateForm(params); errResponder != nil {
		return errResponder
	}

	batchReferences := r.validateConcurrently(params.Body)
	if err := r.locks.DBConnector.AddBatchReferences(r.Context(), batchReferences); err != nil {
		return operations.NewWeaviateBatchingReferencesCreateInternalServerError().
			WithPayload(errPayloadFromSingleErr(err))
	}

	return operations.NewWeaviateBatchingReferencesCreateOK().
		WithPayload(batchReferences.Response())
}

func newReferencesRequest(r *http.Request, deps *state.State, log *telemetry.RequestsLog) *referencesRequest {
	return &referencesRequest{
		Request: r,
		State:   deps,
		log:     log,
	}
}

// a call to lock() should always be followed by a deferred call to unlock()
func (r *referencesRequest) lock() middleware.Responder {
	dbLock, err := r.Database.ConnectorLock()
	if err != nil {
		return operations.NewWeaviateBatchingReferencesCreateUnprocessableEntity().WithPayload(errPayloadFromSingleErr(err))
	}
	r.locks = &rest_api_utils.RequestLocks{
		DBLock:      dbLock,
		DBConnector: dbLock.Connector(),
	}

	return nil
}

func (r *referencesRequest) unlock() {
	r.locks.DBLock.Unlock()
}

func (r *referencesRequest) validateForm(params operations.WeaviateBatchingReferencesCreateParams) middleware.Responder {
	if len(params.Body) == 0 {
		err := fmt.Errorf("length cannot be 0, need at least one reference for batching")
		return operations.NewWeaviateBatchingReferencesCreateUnprocessableEntity().WithPayload(errPayloadFromSingleErr(err))
	}

	return nil
}

func (r *referencesRequest) validateConcurrently(refs []*models.BatchReference) batchmodels.References {
	c := make(chan batchmodels.Reference, len(refs))
	wg := new(sync.WaitGroup)

	// Generate a goroutine for each separate request
	for i, ref := range refs {
		wg.Add(1)
		go r.validateReference(wg, ref, i, &c)
	}

	wg.Wait()
	close(c)
	return referencesChanToSlice(c)
}

func (r *referencesRequest) validateReference(wg *sync.WaitGroup, ref *models.BatchReference,
	i int, resultsC *chan batchmodels.Reference) {
	defer wg.Done()
	var errors []error
	source, err := crossref.ParseSource(string(ref.From))
	if err != nil {
		errors = append(errors, err)
	} else if !source.Local {
		errors = append(errors, fmt.Errorf("source class must always point to the local peer, but got %s",
			source.PeerName))
	}

	target, err := crossref.Parse(string(ref.To))
	if err != nil {
		errors = append(errors, err)
	} else if !target.Local {
		errors = append(errors, fmt.Errorf("importing network references in batch is not possible. "+
			"Please perform a regular non-batch import for network references, got peer %s",
			target.PeerName))
	}

	if len(errors) == 0 {
		err = nil
	} else {
		err = joinErrors(errors)
	}

	if err == nil {
		// Register the request
		go func() {
			r.log.Register(telemetry.TypeREST, telemetry.LocalManipulate)
		}()
	}

	*resultsC <- batchmodels.Reference{
		From:          source,
		To:            target,
		Err:           err,
		OriginalIndex: i,
	}
}

func referencesChanToSlice(c chan batchmodels.Reference) batchmodels.References {
	result := make([]batchmodels.Reference, len(c), len(c))
	for reference := range c {
		result[reference.OriginalIndex] = reference
	}

	return result
}

func joinErrors(errors []error) error {
	errorStrings := []string{}
	for _, err := range errors {
		if err != nil {
			errorStrings = append(errorStrings, err.Error())
		}
	}

	if len(errorStrings) == 0 {
		return nil
	}

	return fmt.Errorf(strings.Join(errorStrings, ", "))
}
<|endoftext|>