Skip to content

Commit

Permalink
swift is back, baby
Browse files Browse the repository at this point in the history
  • Loading branch information
sjml committed Dec 4, 2024
1 parent 77eef4d commit 15b9a84
Show file tree
Hide file tree
Showing 13 changed files with 307 additions and 161 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -152,68 +152,125 @@ class DataReader {
}

class DataWriter {
var data: Data
var data: NSMutableData

init() {
self.data = Data()
self.data = NSMutableData()
}
init(withData: inout Data) {

init(withData: NSMutableData) {
self.data = withData
}

func WriteUInt8(_ ui8: UInt8) {
self.data.append(ui8)
var asData: Data {
return self.data as Data
}

func WriteBool(_ b: Bool) {
self.WriteUInt8(b ? 1 : 0)
func Write(uint8: UInt8) {
var val = uint8;
self.data.append(&val, length: MemoryLayout<UInt8>.size);
}

func WriteInt16(_ i16: Int16) {
var _i16 = Int16(littleEndian: i16)
self.data.append(withUnsafeBytes(of: &_i16, {Data($0)}))
func Write(bool: Bool) {
self.Write(uint8: bool ? 1 : 0)
}

func WriteUInt16(_ ui16: UInt16) {
var _ui16 = UInt16(littleEndian: ui16)
self.data.append(withUnsafeBytes(of: &_ui16, {Data($0)}))
func Write(int16: Int16) {
var val = int16;
self.data.append(&val, length: MemoryLayout<Int16>.size);
}

func WriteInt32(_ i32: Int32) {
var _i32 = Int32(littleEndian: i32)
self.data.append(withUnsafeBytes(of: &_i32, {Data($0)}))
func Write(uint16: UInt16) {
var val = uint16;
self.data.append(&val, length: MemoryLayout<UInt16>.size);
}

func WriteUInt32(_ ui32: UInt32) {
var _ui32 = UInt32(littleEndian: ui32)
self.data.append(withUnsafeBytes(of: &_ui32, {Data($0)}))
func Write(int32: Int32) {
var val = int32;
self.data.append(&val, length: MemoryLayout<Int32>.size);
}

func WriteInt64(_ i64: Int64) {
var _i64 = Int64(littleEndian: i64)
self.data.append(withUnsafeBytes(of: &_i64, {Data($0)}))
func Write(uint32: UInt32) {
var val = uint32;
self.data.append(&val, length: MemoryLayout<UInt32>.size);
}

func WriteUInt64(_ ui64: UInt64) {
var _ui64 = UInt64(littleEndian: ui64)
self.data.append(withUnsafeBytes(of: &_ui64, {Data($0)}))
func Write(int64: Int64) {
var val = int64;
self.data.append(&val, length: MemoryLayout<Int64>.size);
}

func WriteFloat32(_ f: Float32) {
var _f = f
var out = UInt32(littleEndian: withUnsafeBytes(of: &_f, {$0.load(fromByteOffset: 0, as: UInt32.self)}))
self.data.append(withUnsafeBytes(of: &out, {Data($0)}))
func Write(uint64: UInt64) {
var val = uint64;
self.data.append(&val, length: MemoryLayout<UInt64>.size);
}

func WriteFloat64(_ d: Float64) {
var _d = d
var out = UInt64(littleEndian: withUnsafeBytes(of: &_d, {$0.load(fromByteOffset: 0, as: UInt64.self)}))
self.data.append(withUnsafeBytes(of: &out, {Data($0)}))
func Write(float32: Float32) {
var val = float32;
var valOut = UInt32(littleEndian: withUnsafeBytes(of: &val) {
$0.load(fromByteOffset: 0, as: UInt32.self)
})
self.data.append(&valOut, length: MemoryLayout<UInt32>.size);
}

func WriteString(_ s: String) {
let buffer = s.data(using: String.Encoding.utf8)!
self.Write{# STRING_SIZE_TYPE #}({# STRING_SIZE_TYPE #}(buffer.count))
func Write(float64: Float64) {
var val = float64;
var valOut = UInt64(littleEndian: withUnsafeBytes(of: &val) {
$0.load(fromByteOffset: 0, as: UInt64.self)
})
self.data.append(&valOut, length: MemoryLayout<UInt64>.size);
}

func Write(string: String) {
let buffer = string.data(using: .utf8)!
self.Write({# STRING_SIZE_TYPE_LOWER #}: {# STRING_SIZE_TYPE #}(buffer.count))
self.data.append(buffer)
}
}


public class Message {
public func GetMessageType() -> MessageType {
fatalError("GetMessageType must be implemented in subclass")
}
public func WriteBytes(data: NSMutableData, tag: Bool) -> Void {
fatalError("WriteBytes must be implemented in subclass")
}
public func GetSizeInBytes() -> UInt32 {
fatalError("GetSizeInBytes must be implemented in subclass")
}
public class func FromBytes(_ fromData: Data) throws -> Self {
fatalError("FromBytes:fromData must be implemented in subclass")
}
class func FromBytes(dataReader: DataReader) throws -> Self {
fatalError("FromBytes:dataReader must be implemented in subclass")
}

public static func UnpackMessages(_ data: Data) throws -> [Message] {
let dataReader = DataReader(fromData: data)
let headerBytes = dataReader.data[dataReader.currentOffset..<dataReader.currentOffset+4];
guard
let headerLabel = String(data: headerBytes, encoding: String.Encoding.utf8)
else {
throw DataReaderError.InvalidData
}
dataReader.currentOffset += 4
if headerLabel != "BSCI" {
throw DataReaderError.InvalidData
}
let msgCount = try dataReader.GetUInt32();
if msgCount == 0 {
return [Message]()
}
let listData = data.subdata(in: dataReader.currentOffset..<dataReader.data.count)
let msgList: [Message] = try ProcessRawBytes(listData, max: Int(msgCount))
if msgList.count == 0 {
throw DataReaderError.InvalidData
}
if msgList.count != msgCount {
throw DataReaderError.InvalidData
}
return msgList.compactMap { $0 }
}
}

23 changes: 23 additions & 0 deletions beschi/writers/boilerplate/Swift.1.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
extension Array where Element == {# NAMESPACE_PREFIX_DOT #}Message {
public func GetPackedSize() -> Int {
var size: Int = 0
for msg in self {
size += Int(msg.GetSizeInBytes())
}
size += self.count
size += 9
return size
}

public func PackMessages(_ data: NSMutableData) -> Void {
let dataWriter = {# NAMESPACE_PREFIX_DOT #}DataWriter(withData: data)
let headerBytes = "BSCI".data(using: String.Encoding.utf8)!
dataWriter.data.append(headerBytes)
var msgCount = UInt32(littleEndian: UInt32(self.count))
dataWriter.data.append(Swift.withUnsafeBytes(of: &msgCount, {Data($0)}))
for msg in self {
msg.WriteBytes(data: dataWriter.data, tag: true)
}
dataWriter.Write(uint8: 0)
}
}
79 changes: 36 additions & 43 deletions beschi/writers/swift.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
class SwiftWriter(Writer):
language_name = LANGUAGE_NAME
default_extension = ".swift"
in_progress = True # just temporary until I can rethink the data story here

def __init__(self, p: Protocol, extra_args: dict[str,any] = {}):
super().__init__(protocol=p, tab=" ")
Expand Down Expand Up @@ -77,18 +76,18 @@ def deserializer(self, var: Variable, accessor: str):

def serializer(self, var: Variable, accessor: str):
if var.is_list:
self.write_line(f"dataWriter.Write{self.get_native_list_size()}({self.get_native_list_size()}({accessor}{var.name}.count))")
self.write_line(f"dataWriter.Write({self.get_native_list_size().lower()}: {self.get_native_list_size()}({accessor}{var.name}.count))")
self.write_line(f"for el in {accessor}{var.name} {{")
self.indent_level += 1
inner = Variable(self.protocol, "el", var.vartype)
self.serializer(inner, "")
self.indent_level -= 1
self.write_line("}")
elif var.vartype in NUMERIC_TYPE_SIZES or var.vartype == "string":
self.write_line(f"dataWriter.Write{self.type_mapping[var.vartype]}({accessor}{var.name})")
self.write_line(f"dataWriter.Write({self.type_mapping[var.vartype].lower()}: {accessor}{var.name})")
elif var.vartype in self.protocol.enums:
e = self.protocol.enums[var.vartype]
self.write_line(f"dataWriter.Write{self.type_mapping[e.encoding]}({accessor}{var.name}.rawValue)")
self.write_line(f"dataWriter.Write({self.type_mapping[e.encoding].lower()}: {accessor}{var.name}.rawValue)")
else:
self.write_line(f"{accessor}{var.name}.WriteBytes(dataWriter)")

Expand Down Expand Up @@ -144,10 +143,7 @@ def gen_enum(self, ename: str, edata: Enum):

def gen_struct(self, sname: str, sdata: Struct):
if sdata.is_message:
if self.protocol.namespace != None:
self.write_line(f"public struct {sname} : {self.protocol.namespace}_Message {{")
else:
self.write_line(f"public struct {sname} : Message {{")
self.write_line(f"public class {sname}: Message {{")
else:
self.write_line(f"public struct {sname} {{")
self.indent_level += 1
Expand All @@ -166,18 +162,21 @@ def gen_struct(self, sname: str, sdata: Struct):
self.write_line(f"public var {var.name}: {self.type_mapping[var.vartype]}{f' = {default_value}' if default_value else ''}")
self.write_line()

self.write_line("public init() {}")
if sdata.is_message:
self.write_line("public required override init() {}")
else:
self.write_line("public init() {}")
self.write_line()

if sdata.is_message:
self.write_line("public func GetMessageType() -> MessageType {")
self.write_line("public override func GetMessageType() -> MessageType {")
self.indent_level += 1
self.write_line(f"return MessageType.{sname}Type")
self.indent_level -= 1
self.write_line("}")
self.write_line()

self.write_line("public func GetSizeInBytes() -> UInt32 {")
self.write_line("public override func GetSizeInBytes() -> UInt32 {")
self.indent_level += 1
measure_lines, accumulator = self.gen_measurement(sdata, "self.")
[self.write_line(s) for s in measure_lines]
Expand All @@ -189,44 +188,41 @@ def gen_struct(self, sname: str, sdata: Struct):
self.write_line("}")
self.write_line()

self.write_line(f"public static func FromBytes(_ fromData: Data) throws -> {sname} {{")
self.write_line(f"public override class func FromBytes(_ fromData: Data) throws -> Self {{")
self.indent_level += 1
self.write_line("let dr = DataReader(fromData: fromData)")
self.write_line("return try FromBytes(dataReader: dr)")
self.indent_level -= 1
self.write_line("}")
self.write_line()
self.write_line(f"static func FromBytes(dataReader: DataReader) throws -> {sname} {{")
self.write_line(f"override class func FromBytes(dataReader: DataReader) throws -> Self {{")
self.indent_level += 1
else:
self.write_line(f"static func FromBytes(dataReader: DataReader) throws -> {sname} {{")
self.write_line(f"static func FromBytes(dataReader: DataReader) throws -> Self {{")
self.indent_level += 1
decl = "var"
if len(sdata.members) == 0:
if len(sdata.members) == 0 or sdata.is_message:
decl = "let"
self.write_line(f"{decl} n{sname} = {self.type_mapping[sname]}()")
self.write_line(f"{decl} n{sname} = Self.init()")
[self.deserializer(mem, f"n{sname}.") for mem in sdata.members]
self.write_line(f"return n{sname}")
self.indent_level -= 1
self.write_line("}")
self.write_line()

if sdata.is_message:
self.write_line("public func WriteBytes(data: inout Data, tag: Bool) -> Void {")
self.write_line("public override func WriteBytes(data: NSMutableData, tag: Bool) -> Void {")
self.indent_level += 1
self.write_line("let dataWriter = DataWriter(withData: &data)")
self.write_line("let dataWriter = DataWriter(withData: data)")
self.write_line("if (tag) {")
self.indent_level += 1
self.write_line(f"dataWriter.WriteUInt8(MessageType.{sname}Type.rawValue)")
self.write_line(f"dataWriter.Write(uint8: MessageType.{sname}Type.rawValue)")
self.indent_level -= 1
self.write_line("}")
else:
self.write_line("func WriteBytes(_ dataWriter: DataWriter) -> Void {")
self.indent_level += 1
[self.serializer(mem, "self.") for mem in sdata.members]
if sdata.is_message:
self.write_line()
self.write_line("data = dataWriter.data")
self.indent_level -= 1
self.write_line("}")

Expand Down Expand Up @@ -255,27 +251,14 @@ def generate(self) -> str:
self.write_line()
self.write_line()

if self.protocol.namespace != None:
self.write_line(f"public protocol {self.protocol.namespace}_Message {{")
self.indent_level += 1
self.write_line(f"func GetMessageType() -> {self.protocol.namespace}.MessageType")
else:
self.write_line("public protocol Message {")
self.indent_level += 1
self.write_line(f"func GetMessageType() -> MessageType")
self.write_line("func WriteBytes(data: inout Data, tag: Bool) -> Void")
self.write_line("func GetSizeInBytes() -> UInt32")
self.indent_level -= 1
self.write_line("}")
self.write_line()

if self.protocol.namespace != None:
self.write_line(f"public /* namespace */ enum {self.protocol.namespace} {{")
self.indent_level += 1

self.add_boilerplate(substitutions=[
("{# STRING_SIZE_TYPE #}", self.get_native_string_size())
])
self.add_boilerplate([
("{# STRING_SIZE_TYPE #}", self.get_native_string_size()),
("{# STRING_SIZE_TYPE_LOWER #}", self.get_native_string_size().lower()),
], 0)

self.write_line("public enum MessageType: UInt8 {")
self.indent_level += 1
Expand All @@ -287,15 +270,20 @@ def generate(self) -> str:
self.write_line()

if self.protocol.namespace != None:
self.write_line(f"public static func ProcessRawBytes(_ data: Data) throws -> [{self.protocol.namespace}_Message] {{")
self.write_line(f"public static func ProcessRawBytes(_ data: Data, max: Int) throws -> [Message] {{")
self.indent_level += 1
self.write_line(f"var msgList: [{self.protocol.namespace}_Message] = []")
self.write_line(f"var msgList: [Message] = []")
else:
self.write_line(f"public func ProcessRawBytes(_ data: Data) throws -> [Message] {{")
self.write_line(f"public func ProcessRawBytes(_ data: Data, max: Int) throws -> [Message] {{")
self.indent_level += 1
self.write_line("var msgList: [Message] = []")
self.write_line("if max == 0 {")
self.indent_level += 1
self.write_line("return msgList")
self.indent_level -= 1
self.write_line("}")
self.write_line("let dr = DataReader(fromData: data)")
self.write_line("while !dr.IsFinished() {")
self.write_line("while !dr.IsFinished() && (max < 0 || msgList.count < max) {")
self.indent_level += 1
accessor = ""
if self.protocol.namespace != None:
Expand Down Expand Up @@ -346,6 +334,11 @@ def generate(self) -> str:
self.indent_level -= 1
self.write_line("}")

self.write_line()
self.add_boilerplate([
("{# NAMESPACE_PREFIX_DOT #}", f"{self.protocol.namespace}." if self.protocol.namespace != None else ""),
], 1)

self.write_line()
assert self.indent_level == 0

Expand Down
Loading

0 comments on commit 15b9a84

Please sign in to comment.