-
Notifications
You must be signed in to change notification settings - Fork 1
/
nest.go
110 lines (95 loc) · 2.54 KB
/
nest.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package nest
import (
"bytes"
"io"
"sync"
)
// A Writer represents an active nestable writer.
// Each write operation makes a single call to
// the bytes.Buffer's Write method.
// A Writer can be used simultaneously from multiple goroutines;
// it guarantees to serialize access to the buffer.
type Writer struct {
Buf *bytes.Buffer
Depth uint8
Children []*Writer
mutex sync.Mutex
}
// New creates a new Writer with a inner buffer.
func New() *Writer {
return &Writer{
Buf: &bytes.Buffer{},
}
}
// WithParent creates a new Writer from a parent one.
func WithParent(parent *Writer) *Writer {
return WithTitledParent(parent, nil)
}
// WithTitledParent creates a new Writer with a title.
// The title appears as a fist non-indented line on top of the content.
func WithTitledParent(parent *Writer, t []byte) *Writer {
child := &Writer{
Buf: bytes.NewBuffer(format(t, int(parent.Depth))),
Depth: parent.Depth + 1,
}
parent.mutex.Lock()
parent.Children = append(parent.Children, child)
parent.mutex.Unlock()
return child
}
// Write wraps a call to the inner bytes.Buffer's Write method.
// The content p is formatted and indented depending on the Depth of the Writer.
func (n *Writer) Write(p []byte) (int, error) {
p = format(p, int(n.Depth))
n.mutex.Lock()
defer n.mutex.Unlock()
return n.Buf.Write(p)
}
// WriteString wraps a call to a Writer.Write.
func (n *Writer) WriteString(s string) (int, error) {
return n.Write([]byte(s))
}
// WriteTo wraps a call to the inner bytes.Buffer's WriteTo method.
// Once the data on the Writer is fully written,
// then the data of each Children is gonna be written
// The return value i is the number of bytes written; it always fits into an
// int, but it is int64 to match the io.WriterTo interface. Any error
// encountered during the write is also returned.
func (n *Writer) WriteTo(w io.Writer) (i int64, err error) {
n.mutex.Lock()
func() {
defer n.mutex.Unlock()
ii, writeErr := n.Buf.WriteTo(w)
i = i + ii
if writeErr != nil {
err = writeErr
return
}
}()
for _, child := range n.Children {
ii, writeErr := child.WriteTo(w)
i = i + ii
if writeErr != nil {
err = writeErr
return
}
}
return
}
func format(p []byte, depth int) []byte {
if len(p) == 0 {
return p
}
//TODO: optimize p2 slice allocation
var p2, prefix []byte
prefix = bytes.Repeat([]byte{' ', ' ', ' ', ' '}, depth)
for i, line := range bytes.Split(p, []byte{'\n'}) {
if i > 0 {
p2 = append(p2, '\n')
}
p2 = append(p2, prefix...)
p2 = append(p2, line...)
}
p2 = append(p2, '\n')
return p2
}