File: example_test.go

package info (click to toggle)
golang-github-dsnet-golib 0.0~git20171103.1ea1667-1.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 240 kB
  • sloc: makefile: 2
file content (211 lines) | stat: -rw-r--r-- 5,910 bytes parent folder | download | duplicates (2)
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Copyright 2014, Joe Tsai. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

package bufpipe_test

import "io"
import "fmt"
import "time"
import "sync"
import "math/rand"
import "github.com/dsnet/golib/bufpipe"

func randomChars(cnt int, rand *rand.Rand) string {
	data := make([]byte, cnt)
	for idx := range data {
		char := byte(rand.Intn(10 + 26 + 26))
		if char < 10 {
			data[idx] = '0' + char
		} else if char < 10+26 {
			data[idx] = 'A' + char - 10
		} else {
			data[idx] = 'a' + char - 36
		}
	}
	return string(data)
}

// In LineMono mode, the consumer cannot see the written data until the pipe is
// closed. Thus, it is possible for the producer to go back to the front of the
// pipe and record the total number of bytes written out. This functionality is
// useful in cases where a file format's header contains information that is
// dependent on what is eventually written.
func ExampleBufferPipe_lineMono() {
	// The buffer is small enough such that the producer does hit the limit.
	buffer := bufpipe.NewBufferPipe(make([]byte, 256), bufpipe.LineMono)

	rand := rand.New(rand.NewSource(0))
	group := new(sync.WaitGroup)
	group.Add(2)

	// Producer routine.
	go func() {
		defer group.Done()
		defer buffer.Close()

		// In LineMono mode only, it is safe to store a reference to written
		// data and modify later.
		header, _, err := buffer.WriteSlices()
		if err != nil {
			panic(err)
		}

		totalCnt, _ := buffer.Write([]byte("#### "))
		for idx := 0; idx < 8; idx++ {
			data := randomChars(rand.Intn(64), rand) + "\n"

			// So long as the amount of data written has not exceeded the size
			// of the buffer, Write will never fail.
			cnt, err := buffer.Write([]byte(data))
			totalCnt += cnt
			if err == io.ErrShortWrite {
				break
			}

			time.Sleep(100 * time.Millisecond)
		}

		// Write the header afterwards
		copy(header[:4], fmt.Sprintf("%04d", totalCnt))
	}()

	// Consumer routine.
	go func() {
		defer group.Done()

		// In LineMono mode only, a call to ReadSlices is guaranteed to block
		// until the channel is closed. All written data will be made available.
		data, _, _ := buffer.ReadSlices()
		buffer.ReadMark(len(data)) // Technically, this is optional

		fmt.Println(string(data))
	}()

	group.Wait()

	// Output:
	// 0256 kdUhQzHYs2LjaukXEC292UgLOCAPQTCNAKfc0XMNCUuJbsqiHmm6GJMFck
	// whxMYR1k
	// zhMYzktxIv10mIPqBCCwm646E6chwIFZfpX0fjqMu0YKLDhfIMnDq8w9J
	// fQhkT1qEkJfEI0jtbDnIrEXx6G4xMgXEB6auAyBUjPk2jMSgCMVZf8L1VgJemin
	// 2Quy1C5aA00KbYqawNeuXYTvgeUXGu3zyjMUoEIrOx7
	// ecE4dY3ZaTrX03xBY
}

// In LineDual mode, the consumer sees produced data immediately as it becomes
// available. The producer is only allowed to write as much data as the size of
// the underlying buffer. The amount that can be written is independent of the
// operation of the consumer.
func ExampleBufferPipe_lineDual() {
	// The buffer is small enough such that the producer does hit the limit.
	buffer := bufpipe.NewBufferPipe(make([]byte, 256), bufpipe.LineDual)

	rand := rand.New(rand.NewSource(0))
	group := new(sync.WaitGroup)
	group.Add(2)

	// Producer routine.
	go func() {
		defer group.Done()
		defer buffer.Close()

		buffer.Write([]byte("#### ")) // Write a fake header
		for idx := 0; idx < 8; idx++ {
			data := randomChars(rand.Intn(64), rand) + "\n"

			// So long as the amount of data written has not exceeded the size
			// of the buffer, Write will never fail.
			if _, err := buffer.Write([]byte(data)); err == io.ErrShortWrite {
				break
			}

			time.Sleep(100 * time.Millisecond)
		}
	}()

	// Consumer routine.
	go func() {
		defer group.Done()
		for {
			// Reading can be also done using ReadSlices and ReadMark pairs.
			data, _, err := buffer.ReadSlices()
			if err == io.EOF {
				break
			} else if err != nil {
				panic(err)
			}
			buffer.ReadMark(len(data))
			fmt.Print(string(data))
		}
		fmt.Println()
	}()

	group.Wait()

	// Output:
	// #### kdUhQzHYs2LjaukXEC292UgLOCAPQTCNAKfc0XMNCUuJbsqiHmm6GJMFck
	// whxMYR1k
	// zhMYzktxIv10mIPqBCCwm646E6chwIFZfpX0fjqMu0YKLDhfIMnDq8w9J
	// fQhkT1qEkJfEI0jtbDnIrEXx6G4xMgXEB6auAyBUjPk2jMSgCMVZf8L1VgJemin
	// 2Quy1C5aA00KbYqawNeuXYTvgeUXGu3zyjMUoEIrOx7
	// ecE4dY3ZaTrX03xBY
}

// In RingBlock mode, the consumer sees produced data immediately as it becomes
// available. The producer is allowed to write as much data as it wants so long
// as the consumer continues to read the data in the pipe.
func ExampleBufferPipe_ringBlock() {
	// Intentionally small buffer to show that data written into the buffer
	// can exceed the size of the buffer itself.
	buffer := bufpipe.NewBufferPipe(make([]byte, 64), bufpipe.RingBlock)

	rand := rand.New(rand.NewSource(0))
	group := new(sync.WaitGroup)
	group.Add(2)

	// Producer routine.
	go func() {
		defer group.Done()
		defer buffer.Close()

		buffer.Write([]byte("#### ")) // Write a fake header
		for idx := 0; idx < 8; idx++ {
			data := randomChars(rand.Intn(64), rand) + "\n"

			// So long as the amount of data written has not exceeded the size
			// of the buffer, Write will never fail.
			buffer.Write([]byte(data))

			time.Sleep(100 * time.Millisecond)
		}
	}()

	// Consumer routine.
	go func() {
		defer group.Done()

		data := make([]byte, 64)
		for {
			// Reading can also be done using the Read method.
			cnt, err := buffer.Read(data)
			fmt.Print(string(data[:cnt]))
			if err == io.EOF {
				break
			}
		}
		fmt.Println()
	}()

	group.Wait()

	// Output:
	// #### kdUhQzHYs2LjaukXEC292UgLOCAPQTCNAKfc0XMNCUuJbsqiHmm6GJMFck
	// whxMYR1k
	// zhMYzktxIv10mIPqBCCwm646E6chwIFZfpX0fjqMu0YKLDhfIMnDq8w9J
	// fQhkT1qEkJfEI0jtbDnIrEXx6G4xMgXEB6auAyBUjPk2jMSgCMVZf8L1VgJemin
	// 2Quy1C5aA00KbYqawNeuXYTvgeUXGu3zyjMUoEIrOx7
	// ecE4dY3ZaTrX03xBYJ04OzomME36yth76CFmg2zTolzKhYByvZ8
	// FQMuYbcWHLcUu4yL3aBZkwJrbDFUcHpGnBGfbDq4aFlLS5vGOm6mYOjHZll
	// iP0QQKpKp3cz
}