summaryrefslogtreecommitdiff
path: root/internal/fastio/allwriter.go
blob: 071d709b6b45c6c967f8c974a7016e1cd3252ddd (plain)
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
// Copyright (C) 2023  Luke Shumaker <lukeshu@lukeshu.com>
//
// SPDX-License-Identifier: GPL-2.0-or-later

package fastio

import (
	"io"
	"unicode/utf8"

	"git.lukeshu.com/go/lowmemjson/internal/fastio/noescape"
)

// interfaces /////////////////////////////////////////////////////////////////

type RuneWriter interface {
	WriteRune(rune) (int, error)
}

// An AllWriter is the union of several common writer interfaces.
type AllWriter interface {
	io.Writer
	io.ByteWriter
	RuneWriter
	io.StringWriter
}

// implementations ////////////////////////////////////////////////////////////

func WriteByte(w io.Writer, b byte) error {
	var buf [1]byte
	buf[0] = b
	_, err := noescape.Write(w, buf[:])
	return err
}

func WriteRune(w io.Writer, r rune) (int, error) {
	var buf [utf8.UTFMax]byte
	n := utf8.EncodeRune(buf[:], r)
	return noescape.Write(w, buf[:n])
}

func WriteString(w io.Writer, s string) (int, error) {
	return noescape.Write(w, []byte(s))
}

// wrappers ///////////////////////////////////////////////////////////////////

// NNN

type (
	writerNNN        interface{ io.Writer }
	writerNNNWrapper struct{ writerNNN }
)

func (w writerNNNWrapper) WriteByte(b byte) error            { return WriteByte(w, b) }
func (w writerNNNWrapper) WriteRune(r rune) (int, error)     { return WriteRune(w, r) }
func (w writerNNNWrapper) WriteString(s string) (int, error) { return WriteString(w, s) }

// NNY

type (
	writerNNY interface {
		io.Writer
		io.StringWriter
	}
	writerNNYWrapper struct{ writerNNY }
)

func (w writerNNYWrapper) WriteByte(b byte) error        { return WriteByte(w, b) }
func (w writerNNYWrapper) WriteRune(r rune) (int, error) { return WriteRune(w, r) }

// NYN

type (
	writerNYN interface {
		io.Writer
		RuneWriter
	}
	writerNYNWrapper struct{ writerNYN }
)

func (w writerNYNWrapper) WriteByte(b byte) error            { return WriteByte(w, b) }
func (w writerNYNWrapper) WriteString(s string) (int, error) { return WriteString(w, s) }

// NYY

type (
	writerNYY interface {
		io.Writer
		RuneWriter
		io.StringWriter
	}
	writerNYYWrapper struct{ writerNYY }
)

func (w writerNYYWrapper) WriteByte(b byte) error { return WriteByte(w, b) }

// YNN

type (
	writerYNN interface {
		io.Writer
		io.ByteWriter
	}
	writerYNNWrapper struct{ writerYNN }
)

func (w writerYNNWrapper) WriteRune(r rune) (int, error)     { return WriteRune(w, r) }
func (w writerYNNWrapper) WriteString(s string) (int, error) { return WriteString(w, s) }

// YNY

type (
	writerYNY interface {
		io.Writer
		io.ByteWriter
		io.StringWriter
	}
	writerYNYWrapper struct{ writerYNY }
)

func (w writerYNYWrapper) WriteRune(r rune) (int, error) { return WriteRune(w, r) }

// YYN

type (
	writerYYN interface {
		io.Writer
		io.ByteWriter
		RuneWriter
	}
	writerYYNWrapper struct{ writerYYN }
)

func (w writerYYNWrapper) WriteString(s string) (int, error) { return WriteString(w, s) }

// NewAllWriter wraps an io.Writer turning it in to an AllWriter.  If
// the io.Writer already has any of the other write methods, then its
// native version of those methods are used.
func NewAllWriter(inner io.Writer) AllWriter {
	if inner == io.Discard {
		return Discard
	}
	switch inner := inner.(type) {
	// 3 Y bits
	case AllWriter: // YYY:
		return inner
	// 2 Y bits
	case writerNYY:
		return writerNYYWrapper{writerNYY: inner}
	case writerYNY:
		return writerYNYWrapper{writerYNY: inner}
	case writerYYN:
		return writerYYNWrapper{writerYYN: inner}
	// 1 Y bit
	case writerNNY:
		return writerNNYWrapper{writerNNY: inner}
	case writerNYN:
		return writerNYNWrapper{writerNYN: inner}
	case writerYNN:
		return writerYNNWrapper{writerYNN: inner}
	// 0 Y bits
	default: // NNN:
		return writerNNNWrapper{writerNNN: inner}
	}
}

// discard /////////////////////////////////////////////////////////////////////

// Discard is like io.Discard, but implements AllWriter.
var Discard = discard{}

type discard struct{}

func (discard) Write(p []byte) (int, error)       { return len(p), nil }
func (discard) WriteByte(b byte) error            { return nil }
func (discard) WriteRune(r rune) (int, error)     { return 0, nil }
func (discard) WriteString(s string) (int, error) { return len(s), nil }