golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
121.17k stars 17.37k forks source link

proposal: encoding/xml: add iterators Decoder.Tokens, Decoder.RawTokens #68259

Open dolmen opened 5 days ago

dolmen commented 5 days ago

Proposal Details

Add iter.Seq2 iterator methods on encoding/xml.Decoder to iter over tokens and raw tokens.

func (d *Decoder) Tokens() iter.Seq2[Token, error] {
    return func(yield func(Token, error) bool) {
        for {
            token, err := d.Token()
            if err == io.EOF {
                break
            }
            if !yield(token, err) {
                break
            }
            // What should we do here if err != nil?
        }
    }
}

func (d *Decoder) RawTokens() iter.Seq2[Token, error] {
    return func(yield func(Token, error) bool) {
        for {
            token, err := d.RawToken()
            if err == io.EOF {
                break
            }
            if !yield(token, err) {
                break
            }
            // What should we do here if err != nil?
        }
    }
}

Note: I'm not yet sure to like an iterator that handles a stream error this way.

Related:

gabyhelp commented 5 days ago

Related Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

dolmen commented 5 days ago

Note that generic functions can also be written outside the package so the Decoder methods would be purely to allow "native" range-over-func support:

func IterTokens[Token any, Tokenizer interface{ Token() (Token, error) }](tok Tokenizer) iter.Seq2[Token, error] {
    return func(yield func(Token, error) bool) {
        for {
            token, err := tok.Token()
            if err == io.EOF {
                break
            }
            if !yield(token, err) {
                break
            }
        }
    }
}

func IterRawTokens[Token any, Tokenizer interface{ RawToken() (Token, error) }](tok Tokenizer) iter.Seq2[Token, error] {
    return func(yield func(Token, error) bool) {
        for {
            token, err := tok.RawToken()
            if err == io.EOF {
                break
            }
            if !yield(token, err) {
                break
            }
        }
    }
}