-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathByteBuffer+UInt24.swift
124 lines (115 loc) · 4.27 KB
/
ByteBuffer+UInt24.swift
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
/*
* Copyright 2015-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import NIOCore
@usableFromInline
enum UInt24Error: Swift.Error {
case doesNotFitExactlyIntoUInt24
}
extension ByteBuffer {
@discardableResult
@inlinable
internal mutating func setUInt24<T: FixedWidthInteger & UnsignedInteger>(
_ integer: T,
at index: Int,
endianness: Endianness = .big,
as: T.Type = T.self
) -> Int {
precondition(integer >> 24 == 0, "The given unsigned integer does not fit in 24 bit")
let mostSignificant: UInt16
let leastSignificant: UInt8
if T.bitWidth <= UInt8.bitWidth {
mostSignificant = 0
leastSignificant = UInt8(integer)
} else {
mostSignificant = UInt16(truncatingIfNeeded: integer >> UInt8.bitWidth)
leastSignificant = UInt8(truncatingIfNeeded: integer)
}
switch endianness {
case .big:
setInteger(mostSignificant, at: index, endianness: .big)
setInteger(leastSignificant, at: index + 2, endianness: .big)
case .little:
setInteger(leastSignificant, at: index, endianness: .little)
setInteger(mostSignificant, at: index + 1, endianness: .little)
}
return 3
}
@discardableResult
@inlinable
internal mutating func writeUInt24<T: FixedWidthInteger & UnsignedInteger>(
_ integer: T,
endianness: Endianness = .big,
as: T.Type = T.self
) -> Int {
let bytesWritten = setUInt24(integer, at: writerIndex, endianness: endianness)
moveWriterIndex(forwardBy: bytesWritten)
return bytesWritten
}
@discardableResult
@inlinable
internal mutating func writeUInt24WithBoundsCheck<T: FixedWidthInteger>(
_ integer: T,
endianness: Endianness = .big,
as: T.Type = T.self
) throws -> Int {
guard let integer = UInt32(exactly: integer),
integer <= (1 << 24 - 1)
else {
throw UInt24Error.doesNotFitExactlyIntoUInt24
}
return writeUInt24(integer, endianness: endianness)
}
@inlinable
internal func getUInt24(
at index: Int,
endianness: Endianness = .big
) -> UInt32? {
let mostSignificant: UInt16
let leastSignificant: UInt8
switch endianness {
case .big:
guard let uint16 = getInteger(at: index, endianness: .big, as: UInt16.self),
let uint8 = getInteger(at: index + 2, endianness: .big, as: UInt8.self) else { return nil }
mostSignificant = uint16
leastSignificant = uint8
case .little:
guard let uint8 = getInteger(at: index, endianness: .little, as: UInt8.self),
let uint16 = getInteger(at: index + 1, endianness: .little, as: UInt16.self) else { return nil }
mostSignificant = uint16
leastSignificant = uint8
}
return (UInt32(mostSignificant) << 8) &+ UInt32(leastSignificant)
}
@discardableResult
@inlinable
internal mutating func readUInt24(
endianness: Endianness = .big
) -> UInt32? {
guard let integer = getUInt24(at: readerIndex, endianness: endianness) else { return nil }
moveReaderIndex(forwardBy: 3)
return integer
}
@discardableResult
@inlinable
internal mutating func mergeByteBuffers(buffers: [ByteBuffer]) -> ByteBuffer {
let totalLength = buffers.reduce(0){ $0 + $1.readableBytes}
var mergedBuffer = ByteBufferAllocator().buffer(capacity: totalLength)
for buff in buffers {
mergedBuffer.writeBytes(buff.getBytes(at: 0, length: buff.readableBytes) ?? [] )
}
return mergedBuffer
}
}