Skip to content

Commit

Permalink
sans-io approach :)
Browse files Browse the repository at this point in the history
  • Loading branch information
Yu-Vitaqua-fer-Chronos committed Mar 3, 2024
1 parent 923c289 commit 2d5b304
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 160 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"nim.project": ["src/modernnet.nim"]
}
2 changes: 1 addition & 1 deletion modernnet.nimble
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Package

version = "2.1.0"
version = "3.0.0"
author = "Yu-Vitaqua-fer-Chronos"
description = "ModernNet implements a packet reading and writing system, as well as some useful tools for implementing this into your own project!"
license = "Apache-2.0"
Expand Down
8 changes: 4 additions & 4 deletions src/modernnet.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
import "."/modernnet/[
exceptions,
helpers,
network,
buffer,
types
types,
io
]

export
exceptions,
helpers,
network,
buffer,
types
types,
io
40 changes: 12 additions & 28 deletions src/modernnet/buffer.nim
Original file line number Diff line number Diff line change
@@ -1,37 +1,30 @@
import ./[
exceptions,
constants,
types
]

import ./private/stew/endians2
import ./private/[
constants,
utils
]

type
Buffer* = ref object
buf*: seq[byte]
pos*: int

NumberN* = byte | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | float32 | float64
func len*(b: Buffer): int = b.buf.len

func newBuffer*(data: openArray[byte] = newSeq[byte]()): Buffer =
Buffer(buf: @data)

# Writing
func writeNum*[R: NumberN | bool](b: Buffer, value: R) =
func writeNum*[R: SizedNum](b: Buffer, value: R) =
## Writes any numeric type or boolean to a buffer
if (b.pos + sizeof(R)) > b.buf.len:
if (b.pos + sizeof(R)) > b.len:
b.buf.setLen(b.pos + sizeof(R))

when sizeof(R) == 1:
b.buf[b.pos] = cast[byte](value)
elif sizeof(R) == 2:
b.buf[b.pos..<(b.pos+sizeof(R))] = cast[uint16](value).toBytesBE
elif sizeof(R) == 4:
b.buf[b.pos..<(b.pos+sizeof(R))] = cast[uint32](value).toBytesBE
elif sizeof(R) == 8:
b.buf[b.pos..<(b.pos+sizeof(R))] = cast[uint64](value).toBytesBE
else:
{.error: "Serialisation of `" & $R & "` is not implemented!".}
deposit(value, b.buf.toOpenArray(b.pos, b.pos + sizeof(R) - 1))

b.pos += sizeof(R)

Expand Down Expand Up @@ -71,25 +64,16 @@ template writePosition*(b: Buffer, p: Position, format = XZY) =


# Reading
func readNum*[R: NumberN | bool](b: Buffer): R {.raises: [MnEndOfBufferError].} =
func readNum*[R: SizedNum](b: Buffer): R {.raises: [MnEndOfBufferError, ValueError].} =
## Reads any numeric type or boolean from a buffer
if (b.pos + sizeof(R)) > b.buf.len:
raise newException(MnEndOfBufferError, "Reached the end of the buffer while trying to read a " & $R & '!')

result = when sizeof(R) == 1:
cast[R](b.buf[b.pos])
elif sizeof(R) == 2:
cast[R](fromBytesBE(uint16, b.buf[b.pos..<(b.pos+sizeof(R))]))
elif sizeof(R) == 4:
cast[R](fromBytesBE(uint32, b.buf[b.pos..<(b.pos+sizeof(R))]))
elif sizeof(R) == 8:
cast[R](fromBytesBE(uint64, b.buf[b.pos..<(b.pos+sizeof(R))]))
else:
{.error: "Deserialisation of `" & $R & "` is not implemented!".}
result = b.buf.toOpenArray(b.pos, b.pos + sizeof(R) - 1).extract(R)

b.pos += sizeof(R)

func readVarNum*[R: int32 | int64](b: Buffer): R {.raises: [MnEndOfBufferError, MnPacketParsingError].} =
func readVarNum*[R: int32 | int64](b: Buffer): R {.raises: [MnEndOfBufferError, ValueError, MnPacketParsingError].} =
## Reads a VarInt or a VarLong from a buffer
var
position: int8 = 0
Expand Down Expand Up @@ -119,7 +103,7 @@ func readUUID*(b: Buffer): UUID =
## Reads a UUID from a buffer
initUUID(b.readNum[:int64](), b.readNum[:int64]())

func readString*(b: Buffer, maxLength = 32767): string {.raises: [MnEndOfBufferError, MnPacketParsingError].} =
func readString*(b: Buffer, maxLength = 32767): string {.raises: [MnEndOfBufferError, ValueError, MnPacketParsingError].} =
## Reads a string from a buffer
let length = b.readVarNum[:int32]()

Expand Down
61 changes: 61 additions & 0 deletions src/modernnet/io.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#! Copyright 2024 Yu-Vitaqua-fer-Chronos
#!
#! 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 ./[
exceptions,
buffer
]
import ./private/[
constants,
utils
]

using receive_bytes: proc(_: int): seq[byte]

proc read[R: SizedNum](_: typedesc[R], receive_bytes): R =
## Reads any numeric type or boolean from the callback
let bytes = receive_bytes(sizeof(R))
bytes.extract(R)

proc readVar[R: int32 | int64](_: typedesc[R], receive_bytes): R =
## Reads a VarInt or a VarLong from the callback
var
position: int8 = 0
currentByte: int8

while true:
currentByte = read(int8, receive_bytes)
result = result or ((currentByte.R and SegmentBits) shl position)

if (currentByte and ContinueBit) == 0:
break

position += 7

when R is int32:
if position >= VarIntBits:
raise newException(MnPacketParsingError, "VarInt is too big!")

elif R is int64:
if position >= VarLongBits:
raise newException(MnPacketParsingError, "VarLong is too big!")

else:
{.error: "Deserialisation of `" & $R & "` is not implemented!".}

proc readRawPacket*(receive_bytes): (int, Buffer) =
let packetId = readVar(int32, receive_bytes)
let length = readVar(int32, receive_bytes)

return (packetId.int, newBuffer(receive_bytes(length)))
79 changes: 0 additions & 79 deletions src/modernnet/network.nim

This file was deleted.

24 changes: 0 additions & 24 deletions src/modernnet/packets/common.nim

This file was deleted.

File renamed without changes.
51 changes: 51 additions & 0 deletions src/modernnet/private/utils.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#! Copyright 2024 Yu-Vitaqua-fer-Chronos
#!
#! 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 ./stew/endians2

type SizedNum* = bool | byte | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | float32 | float64

template unsignedSize(T: typedesc): typedesc =
when sizeof(T) == 1:
uint8

elif sizeof(T) == 2:
uint16

elif sizeof(T) == 4:
uint32

elif sizeof(T) == 8:
uint64

else:
{.error: "Deserialisation of `" & $T & "` is not implemented!".}

proc extract*[T: SizedNum](oa: openArray[byte], _: typedesc[T]): T =
if oa.len < sizeof(T):
raise newException(ValueError, "The buffer was to small to extract a " & $T & '!')

elif oa.len > sizeof(T):
raise newException(ValueError, "The buffer was to big to extract a " & $T & '!')

cast[T](unsignedSize(T).fromBytesBE(oa.toOpenArray(0, sizeof(T) - 1)))

proc deposit*[T: SizedNum](value: T, oa: out openArray[byte]) =
if oa.len < sizeof(T):
raise newException(ValueError, "The buffer was to small to deposit a " & $T & '!')

let res = cast[unsignedSize(T)](value).toBytesBE()

for i in 0..<sizeof(T):
oa[i] = res[i]
16 changes: 0 additions & 16 deletions src/modernnet/serialisation.nim

This file was deleted.

16 changes: 8 additions & 8 deletions tests/test1.nim
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ test "`readNum` and `writeNum`":

buffer.pos = 0

assert buffer.readNum[:int8]() == a, "int8 test failed!"
assert buffer.readNum[:int16]() == b, "int16 test failed!"
assert buffer.readNum[:int32]() == c, "int32 test failed!"
assert buffer.readNum[:int64]() == d, "int64 test failed!"
assert buffer.readNum[:uint8]() == e, "uint8 test failed!"
assert buffer.readNum[:uint64]() == f, "uint64 test failed!"
assert buffer.readNum[:bool]() == g, "bool test (true) failed!"
assert buffer.readNum[:bool]() == h, "bool test (false) failed!"
check buffer.readNum[:int8]() == a
check buffer.readNum[:int16]() == b
check buffer.readNum[:int32]() == c
check buffer.readNum[:int64]() == d
check buffer.readNum[:uint8]() == e
check buffer.readNum[:uint64]() == f
check buffer.readNum[:bool]() == g
check buffer.readNum[:bool]() == h

test "VarNum tests":
var
Expand Down

0 comments on commit 2d5b304

Please sign in to comment.