From 03f1a7389afeadf9aa2b1d62a38e5cb0a2a7e60d Mon Sep 17 00:00:00 2001 From: Ruben Beltran del Rio Date: Sat, 13 Dec 2025 01:17:52 +0100 Subject: Initial implementation --- Sources/WmapParser/ComponentParser.swift | 78 ++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 Sources/WmapParser/ComponentParser.swift (limited to 'Sources/WmapParser/ComponentParser.swift') diff --git a/Sources/WmapParser/ComponentParser.swift b/Sources/WmapParser/ComponentParser.swift new file mode 100644 index 0000000..c899637 --- /dev/null +++ b/Sources/WmapParser/ComponentParser.swift @@ -0,0 +1,78 @@ +/// Parses a component with its coordinates. +func parseComponent(_ bytes: T, _ start: Int, _ end: Int) -> Component? +where T.Element == UInt8, T.Index == Int { + guard let (label, parenthesisIndex) = extractComponentLabel(bytes, start, end) else { + return nil + } + + guard + let (coordinates, endIndex) = parseCoordinates( + bytes, parenthesisIndex + 1, end) + else { + return nil + } + + let shape = extractComponentShape(bytes, endIndex, end) + + return Component(label: label, coordinates: coordinates, shape: shape) +} + +/// Looks for a component label by taking the string before the first open +/// parenthesis. +@inline(__always) +private func extractComponentLabel(_ bytes: T, _ start: Int, _ end: Int) -> ( + String, Int +)? +where T.Element == UInt8, T.Index == Int { + var index = start + while index < end { + if bytes[index] == kOpenParenthesis { + guard index > start else { return nil } + guard let label = extractTrimmedString(bytes, start, index) else { return nil } + return (label, index) + } + index += 1 + } + return nil +} + +/// Extracts a shape by looking for a shape label in square brackets. +/// If missing, incomplete or invalid, it returns a circle +@inline(__always) +private func extractComponentShape(_ bytes: T, _ start: Int, _ end: Int) -> Shape +where T.Element == UInt8, T.Index == Int { + var index = skipWhitespace(bytes, end, start) + + guard index < end && bytes[index] == kOpenSquareBracket else { return .circle } + + index += 1 + let shapeStart = index + while index < end && bytes[index] != kCloseSquareBracket { index += 1 } + + guard index > shapeStart && index < end else { return .circle } + + let shapeName = bytes[shapeStart..(_ shapeName: T) -> Shape +where T.Element == UInt8, T.Index == Int { + var trimStart = shapeName.startIndex + var trimEnd = shapeName.endIndex + + trimStart = skipWhitespace(shapeName, trimEnd, trimStart) + trimEnd = shaveWhitespace(shapeName, trimStart, trimEnd) + + let trimmedName = shapeName[trimStart..