// 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()) } }
// Write a single feature and return the number of bytes written and any error. func (w *Writer) Write(f feat.Feature) (n int, err error) { defer func() { if err != nil { return } _, err = w.w.Write([]byte{'\n'}) if err != nil { return } n++ }() // Handle Bed types. if f, ok := f.(Bed); ok { if !f.canBed(w.BedType) { return 0, ErrBadBedType } return fmt.Fprintf(w.w, "%*s", w.BedType, f) } // Handle other feature types. if f.Location() == nil { return 0, ErrNoChromField } // Bed3 n, err = fmt.Fprintf(w.w, "%s\t%d\t%d", f.Location(), f.Start(), f.End()) if w.BedType == 3 { return n, err } // Bed4 _n, err := fmt.Fprintf(w.w, "\t%s", f.Name()) n += _n if w.BedType == 4 || err != nil { return n, err } // Bed5 if f, ok := f.(Scorer); ok { _n, err := fmt.Fprintf(w.w, "\t%d", f.Score()) n += _n if err != nil { return n, err } } else { _n, err := fmt.Fprintf(w.w, "\t0") n += _n if err != nil { return n, err } } if w.BedType == 5 { return } // Bed6 if f, ok := f.(feat.Orienter); ok { _n, err := fmt.Fprintf(w.w, "\t%s", seq.Strand(f.Orientation())) n += _n if err != nil { return n, err } } else { _n, err := fmt.Fprintf(w.w, "\t.") n += _n if err != nil { return n, err } } if w.BedType == 6 || w.BedType == 0 { return } // Don't handle Bed12. _n, err = w.w.Write([]byte{'\n'}) n += _n return n, ErrBadBedType }