// Write writes a single feature and return the number of bytes written and any error. // gff.Features are written as a canonical GFF line, seq.Sequences are written as inline // sequence in GFF format (note that only sequences of feat.Moltype DNA, RNA and Protein // are supported). gff.Sequences are not handled as they have a zero length. All other // feat.Feature are written as sequence region metadata lines. func (w *Writer) Write(f feat.Feature) (n int, err error) { if f.Start() >= f.End() { return 0, ErrBadFeature } w.header = true switch f := f.(type) { case *Feature: defer func() { if err != nil { return } _, err = w.w.Write([]byte{'\n'}) if err != nil { return } n++ }() n, err = fmt.Fprintf(w.w, "%s\t%s\t%s\t%d\t%d\t", f.SeqName, f.Source, f.Feature, feat.ZeroToOne(f.FeatStart), f.FeatEnd, ) if err != nil { return n, err } var _n int if f.FeatScore != nil && !math.IsNaN(*f.FeatScore) { if w.Precision < 0 { _n, err = fmt.Fprintf(w.w, "%v", *f.FeatScore) } else { _n, err = fmt.Fprintf(w.w, "%.*f", w.Precision, *f.FeatScore) } if err != nil { return n, err } n += _n } else { _, err = w.w.Write([]byte{'.'}) if err != nil { return n, err } n++ } _n, err = fmt.Fprintf(w.w, "\t%s\t%s", f.FeatStrand, f.FeatFrame, ) n += _n if err != nil { return n, err } if f.FeatAttributes != nil { _n, err = fmt.Fprintf(w.w, "\t%v", f.FeatAttributes) if err != nil { return n, err } n += _n } else if f.Comments != "" { _, err = w.w.Write([]byte{'\t'}) if err != nil { return } n++ } if f.Comments != "" { _n, err = fmt.Fprintf(w.w, "\t%s", f.Comments) n += _n } return n, err case seq.Sequence: sw := fasta.NewWriter(w.w, w.Width) moltype := f.Alphabet().Moltype() if moltype < feat.DNA || moltype > feat.Protein { return 0, ErrNotHandled } sw.IDPrefix = [...][]byte{ feat.DNA: []byte("##DNA "), feat.RNA: []byte("##RNA "), feat.Protein: []byte("##Protein "), }[moltype] sw.SeqPrefix = []byte("##") n, err = sw.Write(f) if err != nil { return n, err } var _n int _n, err = w.w.Write([...][]byte{ feat.DNA: []byte("##end-DNA\n"), feat.RNA: []byte("##end-RNA\n"), feat.Protein: []byte("##end-Protein\n"), }[moltype]) return n + _n, err case Sequence: return 0, ErrNotHandled case *Region: return fmt.Fprintf(w.w, "##sequence-region %s %d %d\n", f.SeqName, feat.ZeroToOne(f.RegionStart), f.RegionEnd) default: return fmt.Fprintf(w.w, "##sequence-region %s %d %d\n", f.Name(), feat.ZeroToOne(f.Start()), f.End()) } }