1
2
3
4
5 package quic
6
7 import (
8 "sync"
9 )
10
11
12
13
14
15
16
17 type pipe struct {
18 start int64
19 end int64
20 head *pipebuf
21 tail *pipebuf
22 }
23
24 type pipebuf struct {
25 off int64
26 b []byte
27 next *pipebuf
28 }
29
30 func (pb *pipebuf) end() int64 {
31 return pb.off + int64(len(pb.b))
32 }
33
34 var pipebufPool = sync.Pool{
35 New: func() any {
36 return &pipebuf{
37 b: make([]byte, 4096),
38 }
39 },
40 }
41
42 func newPipebuf() *pipebuf {
43 return pipebufPool.Get().(*pipebuf)
44 }
45
46 func (b *pipebuf) recycle() {
47 b.off = 0
48 b.next = nil
49 pipebufPool.Put(b)
50 }
51
52
53
54
55
56 func (p *pipe) writeAt(b []byte, off int64) {
57 end := off + int64(len(b))
58 if end > p.end {
59 p.end = end
60 } else if end <= p.start {
61 return
62 }
63
64 if off < p.start {
65
66 trim := p.start - off
67 b = b[trim:]
68 off = p.start
69 }
70
71 if p.head == nil {
72 p.head = newPipebuf()
73 p.head.off = p.start
74 p.tail = p.head
75 }
76 pb := p.head
77 if off >= p.tail.off {
78
79 pb = p.tail
80 }
81 for {
82 pboff := off - pb.off
83 if pboff < int64(len(pb.b)) {
84 n := copy(pb.b[pboff:], b)
85 if n == len(b) {
86 return
87 }
88 off += int64(n)
89 b = b[n:]
90 }
91 if pb.next == nil {
92 pb.next = newPipebuf()
93 pb.next.off = pb.off + int64(len(pb.b))
94 p.tail = pb.next
95 }
96 pb = pb.next
97 }
98 }
99
100
101
102 func (p *pipe) copy(off int64, b []byte) {
103 dst := b[:0]
104 p.read(off, len(b), func(c []byte) error {
105 dst = append(dst, c...)
106 return nil
107 })
108 }
109
110
111
112
113 func (p *pipe) read(off int64, n int, f func([]byte) error) error {
114 if off < p.start {
115 panic("invalid read range")
116 }
117 for pb := p.head; pb != nil && n > 0; pb = pb.next {
118 if off >= pb.end() {
119 continue
120 }
121 b := pb.b[off-pb.off:]
122 if len(b) > n {
123 b = b[:n]
124 }
125 off += int64(len(b))
126 n -= len(b)
127 if err := f(b); err != nil {
128 return err
129 }
130 }
131 if n > 0 {
132 panic("invalid read range")
133 }
134 return nil
135 }
136
137
138
139
140 func (p *pipe) peek(n int64) []byte {
141 pb := p.head
142 if pb == nil {
143 return nil
144 }
145 b := pb.b[p.start-pb.off:]
146 return b[:min(int64(len(b)), n)]
147 }
148
149
150
151
152
153
154 func (p *pipe) availableBuffer() []byte {
155 if p.tail == nil {
156 return nil
157 }
158 return p.tail.b[p.end-p.tail.off:]
159 }
160
161
162 func (p *pipe) discardBefore(off int64) {
163 for p.head != nil && p.head.end() < off {
164 head := p.head
165 p.head = p.head.next
166 head.recycle()
167 }
168 if p.head == nil {
169 p.tail = nil
170 }
171 p.start = off
172 p.end = max(p.end, off)
173 }
174
View as plain text