This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
package svg
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
type (
|
||||
elementReader[T Tag, A Attribute, C MarshalerReader] struct {
|
||||
element Element[T, A, C]
|
||||
buf *bytes.Buffer
|
||||
|
||||
openTagRead bool
|
||||
numChildrenRead int
|
||||
childrenRead bool
|
||||
childReader io.Reader
|
||||
closeTagRead bool
|
||||
}
|
||||
)
|
||||
|
||||
func newElementReader[T Tag, A Attribute, C MarshalerReader](e Element[T, A, C]) *elementReader[T, A, C] {
|
||||
return &elementReader[T, A, C]{
|
||||
element: e,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *elementReader[T, A, C]) Read(p []byte) (totalRead int, err error) {
|
||||
if e.buf == nil {
|
||||
// just started reading.
|
||||
// buffer the open tag
|
||||
|
||||
e.buf = new(bytes.Buffer)
|
||||
|
||||
// bytes.Buffer never returns an error on Write()
|
||||
e.buf.WriteByte('<')
|
||||
e.buf.WriteString(e.element.PrintTag())
|
||||
for _, a := range e.element.Attributes {
|
||||
e.buf.WriteByte(' ')
|
||||
e.buf.WriteString(PrintAttribute(a))
|
||||
}
|
||||
e.buf.WriteByte('>')
|
||||
}
|
||||
|
||||
if !e.openTagRead {
|
||||
// read the open tag
|
||||
|
||||
n, err := e.buf.Read(p)
|
||||
totalRead += n
|
||||
if (err != nil && !errors.Is(err, io.EOF)) || n >= len(p) {
|
||||
return totalRead, err
|
||||
}
|
||||
|
||||
// done reading the open tag
|
||||
|
||||
e.openTagRead = true
|
||||
e.buf.Reset()
|
||||
|
||||
p = p[n:]
|
||||
}
|
||||
|
||||
// read the children
|
||||
|
||||
for ; e.numChildrenRead < len(e.element.Children); e.numChildrenRead += 1 {
|
||||
if e.childReader == nil {
|
||||
e.childReader = e.element.Children[e.numChildrenRead].GetMarkupReader()
|
||||
}
|
||||
|
||||
// read the child
|
||||
|
||||
n, err := e.childReader.Read(p)
|
||||
totalRead += n
|
||||
if (err != nil && !errors.Is(err, io.EOF)) || n >= len(p) {
|
||||
return totalRead, err
|
||||
}
|
||||
|
||||
// done reading the child
|
||||
|
||||
e.childReader = nil
|
||||
|
||||
p = p[n:]
|
||||
}
|
||||
|
||||
if !e.childrenRead {
|
||||
// done reading the children
|
||||
|
||||
e.childrenRead = true
|
||||
|
||||
// buffer the close tag
|
||||
|
||||
e.buf.Write([]byte("</"))
|
||||
e.buf.WriteString(e.element.PrintTag())
|
||||
e.buf.WriteByte('>')
|
||||
}
|
||||
|
||||
if !e.closeTagRead {
|
||||
n, err := e.buf.Read(p)
|
||||
totalRead += n
|
||||
if (err != nil && !errors.Is(err, io.EOF)) || n >= len(p) {
|
||||
return totalRead, err
|
||||
}
|
||||
|
||||
// done writing the close tag
|
||||
|
||||
e.closeTagRead = true
|
||||
return totalRead, err
|
||||
}
|
||||
|
||||
return 0, io.EOF
|
||||
}
|
||||
Reference in New Issue
Block a user