1package etw
2
3import (
4	"math"
5	"unsafe"
6)
7
8// FieldOpt defines the option function type that can be passed to
9// Provider.WriteEvent to add fields to the event.
10type FieldOpt func(em *EventMetadata, ed *EventData)
11
12// WithFields returns the variadic arguments as a single slice.
13func WithFields(opts ...FieldOpt) []FieldOpt {
14	return opts
15}
16
17// BoolField adds a single bool field to the event.
18func BoolField(name string, value bool) FieldOpt {
19	return func(em *EventMetadata, ed *EventData) {
20		em.WriteField(name, InTypeUint8, OutTypeBoolean, 0)
21		bool8 := uint8(0)
22		if value {
23			bool8 = uint8(1)
24		}
25		ed.WriteUint8(bool8)
26	}
27}
28
29// BoolArray adds an array of bool to the event.
30func BoolArray(name string, values []bool) FieldOpt {
31	return func(em *EventMetadata, ed *EventData) {
32		em.WriteArray(name, InTypeUint8, OutTypeBoolean, 0)
33		ed.WriteUint16(uint16(len(values)))
34		for _, v := range values {
35			bool8 := uint8(0)
36			if v {
37				bool8 = uint8(1)
38			}
39			ed.WriteUint8(bool8)
40		}
41	}
42}
43
44// StringField adds a single string field to the event.
45func StringField(name string, value string) FieldOpt {
46	return func(em *EventMetadata, ed *EventData) {
47		em.WriteField(name, InTypeANSIString, OutTypeUTF8, 0)
48		ed.WriteString(value)
49	}
50}
51
52// StringArray adds an array of string to the event.
53func StringArray(name string, values []string) FieldOpt {
54	return func(em *EventMetadata, ed *EventData) {
55		em.WriteArray(name, InTypeANSIString, OutTypeUTF8, 0)
56		ed.WriteUint16(uint16(len(values)))
57		for _, v := range values {
58			ed.WriteString(v)
59		}
60	}
61}
62
63// IntField adds a single int field to the event.
64func IntField(name string, value int) FieldOpt {
65	switch unsafe.Sizeof(value) {
66	case 4:
67		return Int32Field(name, int32(value))
68	case 8:
69		return Int64Field(name, int64(value))
70	default:
71		panic("Unsupported int size")
72	}
73}
74
75// IntArray adds an array of int to the event.
76func IntArray(name string, values []int) FieldOpt {
77	inType := InTypeNull
78	var writeItem func(*EventData, int)
79	switch unsafe.Sizeof(values[0]) {
80	case 4:
81		inType = InTypeInt32
82		writeItem = func(ed *EventData, item int) { ed.WriteInt32(int32(item)) }
83	case 8:
84		inType = InTypeInt64
85		writeItem = func(ed *EventData, item int) { ed.WriteInt64(int64(item)) }
86	default:
87		panic("Unsupported int size")
88	}
89
90	return func(em *EventMetadata, ed *EventData) {
91		em.WriteArray(name, inType, OutTypeDefault, 0)
92		ed.WriteUint16(uint16(len(values)))
93		for _, v := range values {
94			writeItem(ed, v)
95		}
96	}
97}
98
99// Int8Field adds a single int8 field to the event.
100func Int8Field(name string, value int8) FieldOpt {
101	return func(em *EventMetadata, ed *EventData) {
102		em.WriteField(name, InTypeInt8, OutTypeDefault, 0)
103		ed.WriteInt8(value)
104	}
105}
106
107// Int8Array adds an array of int8 to the event.
108func Int8Array(name string, values []int8) FieldOpt {
109	return func(em *EventMetadata, ed *EventData) {
110		em.WriteArray(name, InTypeInt8, OutTypeDefault, 0)
111		ed.WriteUint16(uint16(len(values)))
112		for _, v := range values {
113			ed.WriteInt8(v)
114		}
115	}
116}
117
118// Int16Field adds a single int16 field to the event.
119func Int16Field(name string, value int16) FieldOpt {
120	return func(em *EventMetadata, ed *EventData) {
121		em.WriteField(name, InTypeInt16, OutTypeDefault, 0)
122		ed.WriteInt16(value)
123	}
124}
125
126// Int16Array adds an array of int16 to the event.
127func Int16Array(name string, values []int16) FieldOpt {
128	return func(em *EventMetadata, ed *EventData) {
129		em.WriteArray(name, InTypeInt16, OutTypeDefault, 0)
130		ed.WriteUint16(uint16(len(values)))
131		for _, v := range values {
132			ed.WriteInt16(v)
133		}
134	}
135}
136
137// Int32Field adds a single int32 field to the event.
138func Int32Field(name string, value int32) FieldOpt {
139	return func(em *EventMetadata, ed *EventData) {
140		em.WriteField(name, InTypeInt32, OutTypeDefault, 0)
141		ed.WriteInt32(value)
142	}
143}
144
145// Int32Array adds an array of int32 to the event.
146func Int32Array(name string, values []int32) FieldOpt {
147	return func(em *EventMetadata, ed *EventData) {
148		em.WriteArray(name, InTypeInt32, OutTypeDefault, 0)
149		ed.WriteUint16(uint16(len(values)))
150		for _, v := range values {
151			ed.WriteInt32(v)
152		}
153	}
154}
155
156// Int64Field adds a single int64 field to the event.
157func Int64Field(name string, value int64) FieldOpt {
158	return func(em *EventMetadata, ed *EventData) {
159		em.WriteField(name, InTypeInt64, OutTypeDefault, 0)
160		ed.WriteInt64(value)
161	}
162}
163
164// Int64Array adds an array of int64 to the event.
165func Int64Array(name string, values []int64) FieldOpt {
166	return func(em *EventMetadata, ed *EventData) {
167		em.WriteArray(name, InTypeInt64, OutTypeDefault, 0)
168		ed.WriteUint16(uint16(len(values)))
169		for _, v := range values {
170			ed.WriteInt64(v)
171		}
172	}
173}
174
175// UintField adds a single uint field to the event.
176func UintField(name string, value uint) FieldOpt {
177	switch unsafe.Sizeof(value) {
178	case 4:
179		return Uint32Field(name, uint32(value))
180	case 8:
181		return Uint64Field(name, uint64(value))
182	default:
183		panic("Unsupported uint size")
184	}
185}
186
187// UintArray adds an array of uint to the event.
188func UintArray(name string, values []uint) FieldOpt {
189	inType := InTypeNull
190	var writeItem func(*EventData, uint)
191	switch unsafe.Sizeof(values[0]) {
192	case 4:
193		inType = InTypeUint32
194		writeItem = func(ed *EventData, item uint) { ed.WriteUint32(uint32(item)) }
195	case 8:
196		inType = InTypeUint64
197		writeItem = func(ed *EventData, item uint) { ed.WriteUint64(uint64(item)) }
198	default:
199		panic("Unsupported uint size")
200	}
201
202	return func(em *EventMetadata, ed *EventData) {
203		em.WriteArray(name, inType, OutTypeDefault, 0)
204		ed.WriteUint16(uint16(len(values)))
205		for _, v := range values {
206			writeItem(ed, v)
207		}
208	}
209}
210
211// Uint8Field adds a single uint8 field to the event.
212func Uint8Field(name string, value uint8) FieldOpt {
213	return func(em *EventMetadata, ed *EventData) {
214		em.WriteField(name, InTypeUint8, OutTypeDefault, 0)
215		ed.WriteUint8(value)
216	}
217}
218
219// Uint8Array adds an array of uint8 to the event.
220func Uint8Array(name string, values []uint8) FieldOpt {
221	return func(em *EventMetadata, ed *EventData) {
222		em.WriteArray(name, InTypeUint8, OutTypeDefault, 0)
223		ed.WriteUint16(uint16(len(values)))
224		for _, v := range values {
225			ed.WriteUint8(v)
226		}
227	}
228}
229
230// Uint16Field adds a single uint16 field to the event.
231func Uint16Field(name string, value uint16) FieldOpt {
232	return func(em *EventMetadata, ed *EventData) {
233		em.WriteField(name, InTypeUint16, OutTypeDefault, 0)
234		ed.WriteUint16(value)
235	}
236}
237
238// Uint16Array adds an array of uint16 to the event.
239func Uint16Array(name string, values []uint16) FieldOpt {
240	return func(em *EventMetadata, ed *EventData) {
241		em.WriteArray(name, InTypeUint16, OutTypeDefault, 0)
242		ed.WriteUint16(uint16(len(values)))
243		for _, v := range values {
244			ed.WriteUint16(v)
245		}
246	}
247}
248
249// Uint32Field adds a single uint32 field to the event.
250func Uint32Field(name string, value uint32) FieldOpt {
251	return func(em *EventMetadata, ed *EventData) {
252		em.WriteField(name, InTypeUint32, OutTypeDefault, 0)
253		ed.WriteUint32(value)
254	}
255}
256
257// Uint32Array adds an array of uint32 to the event.
258func Uint32Array(name string, values []uint32) FieldOpt {
259	return func(em *EventMetadata, ed *EventData) {
260		em.WriteArray(name, InTypeUint32, OutTypeDefault, 0)
261		ed.WriteUint16(uint16(len(values)))
262		for _, v := range values {
263			ed.WriteUint32(v)
264		}
265	}
266}
267
268// Uint64Field adds a single uint64 field to the event.
269func Uint64Field(name string, value uint64) FieldOpt {
270	return func(em *EventMetadata, ed *EventData) {
271		em.WriteField(name, InTypeUint64, OutTypeDefault, 0)
272		ed.WriteUint64(value)
273	}
274}
275
276// Uint64Array adds an array of uint64 to the event.
277func Uint64Array(name string, values []uint64) FieldOpt {
278	return func(em *EventMetadata, ed *EventData) {
279		em.WriteArray(name, InTypeUint64, OutTypeDefault, 0)
280		ed.WriteUint16(uint16(len(values)))
281		for _, v := range values {
282			ed.WriteUint64(v)
283		}
284	}
285}
286
287// UintptrField adds a single uintptr field to the event.
288func UintptrField(name string, value uintptr) FieldOpt {
289	inType := InTypeNull
290	var writeItem func(*EventData, uintptr)
291	switch unsafe.Sizeof(value) {
292	case 4:
293		inType = InTypeHexInt32
294		writeItem = func(ed *EventData, item uintptr) { ed.WriteUint32(uint32(item)) }
295	case 8:
296		inType = InTypeHexInt64
297		writeItem = func(ed *EventData, item uintptr) { ed.WriteUint64(uint64(item)) }
298	default:
299		panic("Unsupported uintptr size")
300	}
301
302	return func(em *EventMetadata, ed *EventData) {
303		em.WriteField(name, inType, OutTypeDefault, 0)
304		writeItem(ed, value)
305	}
306}
307
308// UintptrArray adds an array of uintptr to the event.
309func UintptrArray(name string, values []uintptr) FieldOpt {
310	inType := InTypeNull
311	var writeItem func(*EventData, uintptr)
312	switch unsafe.Sizeof(values[0]) {
313	case 4:
314		inType = InTypeHexInt32
315		writeItem = func(ed *EventData, item uintptr) { ed.WriteUint32(uint32(item)) }
316	case 8:
317		inType = InTypeHexInt64
318		writeItem = func(ed *EventData, item uintptr) { ed.WriteUint64(uint64(item)) }
319	default:
320		panic("Unsupported uintptr size")
321	}
322
323	return func(em *EventMetadata, ed *EventData) {
324		em.WriteArray(name, inType, OutTypeDefault, 0)
325		ed.WriteUint16(uint16(len(values)))
326		for _, v := range values {
327			writeItem(ed, v)
328		}
329	}
330}
331
332// Float32Field adds a single float32 field to the event.
333func Float32Field(name string, value float32) FieldOpt {
334	return func(em *EventMetadata, ed *EventData) {
335		em.WriteField(name, InTypeFloat, OutTypeDefault, 0)
336		ed.WriteUint32(math.Float32bits(value))
337	}
338}
339
340// Float32Array adds an array of float32 to the event.
341func Float32Array(name string, values []float32) FieldOpt {
342	return func(em *EventMetadata, ed *EventData) {
343		em.WriteArray(name, InTypeFloat, OutTypeDefault, 0)
344		ed.WriteUint16(uint16(len(values)))
345		for _, v := range values {
346			ed.WriteUint32(math.Float32bits(v))
347		}
348	}
349}
350
351// Float64Field adds a single float64 field to the event.
352func Float64Field(name string, value float64) FieldOpt {
353	return func(em *EventMetadata, ed *EventData) {
354		em.WriteField(name, InTypeDouble, OutTypeDefault, 0)
355		ed.WriteUint64(math.Float64bits(value))
356	}
357}
358
359// Float64Array adds an array of float64 to the event.
360func Float64Array(name string, values []float64) FieldOpt {
361	return func(em *EventMetadata, ed *EventData) {
362		em.WriteArray(name, InTypeDouble, OutTypeDefault, 0)
363		ed.WriteUint16(uint16(len(values)))
364		for _, v := range values {
365			ed.WriteUint64(math.Float64bits(v))
366		}
367	}
368}
369
370// Struct adds a nested struct to the event, the FieldOpts in the opts argument
371// are used to specify the fields of the struct.
372func Struct(name string, opts ...FieldOpt) FieldOpt {
373	return func(em *EventMetadata, ed *EventData) {
374		em.WriteStruct(name, uint8(len(opts)), 0)
375		for _, opt := range opts {
376			opt(em, ed)
377		}
378	}
379}
380