Skip to content

Commit a7d758a

Browse files
authored
Merge pull request #88 from Eragoneq/serialization-update
Update Serialization.kt with auto functionality
2 parents d47d9d3 + 6ff3d74 commit a7d758a

File tree

2 files changed

+346
-12
lines changed

2 files changed

+346
-12
lines changed

ipv8/src/main/java/nl/tudelft/ipv8/messaging/Serialization.kt

Lines changed: 129 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ package nl.tudelft.ipv8.messaging
22

33
import java.nio.Buffer
44
import java.nio.ByteBuffer
5+
import kotlin.reflect.full.isSubclassOf
6+
import kotlin.reflect.full.memberProperties
7+
import kotlin.reflect.full.primaryConstructor
58

69
const val SERIALIZED_USHORT_SIZE = 2
710
const val SERIALIZED_UINT_SIZE = 4
11+
const val SERIALIZED_INT_SIZE = 4
812
const val SERIALIZED_ULONG_SIZE = 8
9-
const val SERIALIZED_LONG_SIZE = 4
13+
const val SERIALIZED_LONG_SIZE = 8
1014
const val SERIALIZED_UBYTE_SIZE = 1
1115

1216
const val SERIALIZED_PUBLIC_KEY_SIZE = 74
@@ -20,6 +24,81 @@ interface Serializable {
2024

2125
interface Deserializable<T> {
2226
fun deserialize(buffer: ByteArray, offset: Int = 0): Pair<T, Int>
27+
28+
}
29+
30+
/**
31+
* Serializes the object and returns the buffer.
32+
* Alternative to manually defining the serialize function.
33+
*/
34+
interface AutoSerializable : Serializable {
35+
override fun serialize(): ByteArray {
36+
return this::class.primaryConstructor!!.parameters.map { param ->
37+
val value =
38+
this.javaClass.kotlin.memberProperties.find { it.name == param.name }!!.get(this)
39+
simpleSerialize(value)
40+
}.reduce { acc, bytes -> acc + bytes }
41+
}
42+
}
43+
44+
///**
45+
// * Deserializes the object from the buffer and returns the object and the new offset.
46+
// * Alternative to manually defining the deserialize function.
47+
// */
48+
//inline fun <reified T> Deserializable<T>.autoDeserialize(buffer: ByteArray, offset: Int = 0): Pair<T, Int> {
49+
// TODO()
50+
//}
51+
52+
fun <U> simpleSerialize(data: U): ByteArray {
53+
return when (data) {
54+
is Int -> serializeInt(data)
55+
is Long -> serializeLong(data)
56+
is UByte -> serializeUChar(data)
57+
is UInt -> serializeUInt(data)
58+
is UShort -> serializeUShort(data.toInt())
59+
is ULong -> serializeULong(data)
60+
is String -> serializeVarLen(data.toByteArray())
61+
is ByteArray -> serializeVarLen(data)
62+
is Boolean -> serializeBool(data)
63+
is Enum<*> -> serializeUInt(data.ordinal.toUInt())
64+
is Serializable -> data.serialize()
65+
else -> throw IllegalArgumentException("Unsupported serialization type")
66+
}
67+
}
68+
69+
inline fun <reified U> simpleDeserialize(buffer: ByteArray, offset: Int = 0): Pair<U, Int> {
70+
val (value, off) = when (U::class) {
71+
Int::class -> Pair(deserializeInt(buffer, offset) as U, SERIALIZED_INT_SIZE)
72+
Long::class -> Pair(deserializeLong(buffer, offset) as U, SERIALIZED_LONG_SIZE)
73+
UByte::class -> Pair(deserializeUChar(buffer, offset) as U, SERIALIZED_UBYTE_SIZE)
74+
UShort::class -> Pair(
75+
deserializeUShort(buffer, offset).toUShort() as U,
76+
SERIALIZED_USHORT_SIZE
77+
)
78+
79+
UInt::class -> Pair(deserializeUInt(buffer, offset) as U, SERIALIZED_UINT_SIZE)
80+
ULong::class -> Pair(deserializeULong(buffer, offset) as U, SERIALIZED_ULONG_SIZE)
81+
String::class -> {
82+
val (data, len) = deserializeVarLen(buffer, offset)
83+
Pair(data.decodeToString() as U, len)
84+
}
85+
86+
ByteArray::class -> {
87+
val (data, len) = deserializeVarLen(buffer, offset)
88+
Pair(data as U, len)
89+
}
90+
91+
Boolean::class -> Pair(deserializeBool(buffer, offset) as U, 1)
92+
else -> {
93+
println("Enum: ${U::class.qualifiedName}")
94+
if (U::class.isSubclassOf(Enum::class)) {
95+
val ordinal = deserializeUInt(buffer, offset).toInt()
96+
val values = U::class.java.enumConstants
97+
Pair(values[ordinal] as U, SERIALIZED_UINT_SIZE)
98+
} else throw IllegalArgumentException("Unsupported deserialization type")
99+
}
100+
}
101+
return (value to (offset + off))
23102
}
24103

25104
fun serializeBool(data: Boolean): ByteArray {
@@ -40,10 +119,21 @@ fun serializeUShort(value: Int): ByteArray {
40119
return bytes
41120
}
42121

122+
fun serializeUShort(value: UShort): ByteArray {
123+
val bytes = ByteBuffer.allocate(SERIALIZED_USHORT_SIZE)
124+
bytes.putShort(value.toShort())
125+
return bytes.array()
126+
}
127+
43128
fun deserializeUShort(buffer: ByteArray, offset: Int = 0): Int {
44129
return (((buffer[offset].toInt() and 0xFF) shl 8) or (buffer[offset + 1].toInt() and 0xFF))
45130
}
46131

132+
fun deserializeRealUShort(buffer: ByteArray, offset: Int = 0): UShort {
133+
val buf = ByteBuffer.wrap(buffer, offset, SERIALIZED_USHORT_SIZE)
134+
return buf.short.toUShort()
135+
}
136+
47137
fun serializeUInt(value: UInt): ByteArray {
48138
val bytes = UByteArray(SERIALIZED_UINT_SIZE)
49139
for (i in 0 until SERIALIZED_UINT_SIZE) {
@@ -80,7 +170,7 @@ fun deserializeULong(buffer: ByteArray, offset: Int = 0): ULong {
80170

81171
fun serializeLong(value: Long): ByteArray {
82172
val buffer = ByteBuffer.allocate(SERIALIZED_LONG_SIZE)
83-
buffer.putInt(value.toInt())
173+
buffer.putLong(value)
84174
return buffer.array()
85175
}
86176

@@ -89,7 +179,20 @@ fun deserializeLong(bytes: ByteArray, offset: Int = 0): Long {
89179
buffer.put(bytes.copyOfRange(offset, offset + SERIALIZED_LONG_SIZE))
90180
// In JDK 8 this returns a Buffer.
91181
(buffer as Buffer).flip()
92-
return buffer.int.toLong()
182+
return buffer.long
183+
}
184+
185+
fun serializeInt(value: Int): ByteArray {
186+
val buffer = ByteBuffer.allocate(SERIALIZED_INT_SIZE)
187+
buffer.putInt(value)
188+
return buffer.array()
189+
}
190+
191+
fun deserializeInt(bytes: ByteArray, offset: Int = 0): Int {
192+
val buffer = ByteBuffer.allocate(SERIALIZED_INT_SIZE)
193+
buffer.put(bytes.copyOfRange(offset, offset + SERIALIZED_INT_SIZE))
194+
buffer.flip()
195+
return buffer.int
93196
}
94197

95198
fun serializeUChar(char: UByte): ByteArray {
@@ -107,8 +210,10 @@ fun serializeVarLen(bytes: ByteArray): ByteArray {
107210

108211
fun deserializeVarLen(buffer: ByteArray, offset: Int = 0): Pair<ByteArray, Int> {
109212
val len = deserializeUInt(buffer, offset).toInt()
110-
val payload = buffer.copyOfRange(offset + SERIALIZED_UINT_SIZE,
111-
offset + SERIALIZED_UINT_SIZE + len)
213+
val payload = buffer.copyOfRange(
214+
offset + SERIALIZED_UINT_SIZE,
215+
offset + SERIALIZED_UINT_SIZE + len
216+
)
112217
return Pair(payload, SERIALIZED_UINT_SIZE + len)
113218
}
114219

@@ -117,19 +222,31 @@ fun deserializeRecursively(buffer: ByteArray, offset: Int = 0): Array<ByteArray>
117222
return arrayOf()
118223
}
119224
val len = deserializeUInt(buffer, offset).toInt()
120-
val payload = buffer.copyOfRange(offset + SERIALIZED_UINT_SIZE,
121-
offset + SERIALIZED_UINT_SIZE + len)
122-
return arrayOf(payload) + deserializeRecursively(buffer.copyOfRange(offset + SERIALIZED_UINT_SIZE + len,
123-
buffer.size), offset)
225+
val payload = buffer.copyOfRange(
226+
offset + SERIALIZED_UINT_SIZE,
227+
offset + SERIALIZED_UINT_SIZE + len
228+
)
229+
return arrayOf(payload) + deserializeRecursively(
230+
buffer.copyOfRange(
231+
offset + SERIALIZED_UINT_SIZE + len,
232+
buffer.size
233+
), offset
234+
)
124235
}
125236

126-
fun deserializeAmount(buffer: ByteArray, amount: Int, offset: Int = 0): Pair<Array<ByteArray>, ByteArray> {
237+
fun deserializeAmount(
238+
buffer: ByteArray,
239+
amount: Int,
240+
offset: Int = 0
241+
): Pair<Array<ByteArray>, ByteArray> {
127242
val returnValues = arrayListOf<ByteArray>()
128243
var localOffset = offset
129244
for (i in 0 until amount) {
130245
val len = deserializeUInt(buffer, localOffset).toInt()
131-
val payload = buffer.copyOfRange(localOffset + SERIALIZED_UINT_SIZE,
132-
localOffset + SERIALIZED_UINT_SIZE + len)
246+
val payload = buffer.copyOfRange(
247+
localOffset + SERIALIZED_UINT_SIZE,
248+
localOffset + SERIALIZED_UINT_SIZE + len
249+
)
133250
localOffset += SERIALIZED_UINT_SIZE + len
134251
returnValues.add(payload)
135252
}

0 commit comments

Comments
 (0)