MetadataStruct moved to its own module.

Signed-off-by: Adam Rocska <adam.rocska@adams.solutions>
This commit is contained in:
Adam Rocska 2020-05-11 13:41:38 +02:00
parent 5db534cb55
commit 3b80256856
5 changed files with 56 additions and 72 deletions

View File

@ -35,7 +35,7 @@ let package = Package(
.target(
name: "MaxMindDBReader",
dependencies: ["Index", "MaxMindDecoder"],
dependencies: ["Index", "Metadata", "MaxMindDecoder"],
path: "Sources/MaxMindDBReader"
),
.target(

View File

@ -1,6 +1,7 @@
import Foundation
import MaxMindDecoder
import Index
import Metadata
public class InMemoryReader {
@ -10,7 +11,7 @@ public class InMemoryReader {
private let databaseContent: Data
private let indexRange: Range<Data.Index>
let metadata: MetadataStruct
let metadata: Metadata
public init(data: Data) throws {
databaseContent = data
@ -30,7 +31,7 @@ public class InMemoryReader {
upper: databaseContent.endIndex
))
let rawMetadata = databaseContent.subdata(in: metadataRange)
guard let metadata = MetadataStruct(rawMetadata) else {
guard let metadata = Metadata(rawMetadata) else {
throw ReaderError.corruptMetadata
}

View File

@ -1,49 +0,0 @@
import Foundation
import MaxMindDecoder
struct MetadataStruct {
let nodeCount: UInt32
let recordSize: UInt16
let ipVersion: UInt16
let databaseType: String
let languages: [String]
let binaryFormatMajorVersion: UInt16
let binaryFormatMinorVersion: UInt16
let buildEpoch: UInt64
let description: [String: String]
var nodeByteSize: UInt16 { get { return recordSize / 4 } }
var searchTreeSize: UInt64 { get { return UInt64(nodeCount * UInt32(nodeByteSize)) } }
init?(_ iterator: MaxMindIterator) {
guard let mapControlByte = iterator.next() else { return nil }
if mapControlByte.type != .map { return nil }
let decoder = MaxMindDecoder(inputEndianness: .big)
let decoded: [String: Any] = decoder.decode(iterator, size: Int(mapControlByte.payloadSize))
guard let nodeCount = decoded["node_count"] as? UInt32 else { return nil }
guard let recordSize = decoded["record_size"] as? UInt16 else { return nil }
guard let ipVersion = decoded["ip_version"] as? UInt16 else { return nil }
guard let databaseType = decoded["database_type"] as? String else { return nil }
guard let languages = decoded["languages"] as? [String] else { return nil }
guard let majorVersion = decoded["binary_format_major_version"] as? UInt16 else { return nil }
guard let minorVersion = decoded["binary_format_minor_version"] as? UInt16 else { return nil }
guard let buildEpoch = decoded["build_epoch"] as? UInt64 else { return nil }
guard let description = decoded["description"] as? [String: String] else { return nil }
self.nodeCount = nodeCount
self.recordSize = recordSize
self.ipVersion = ipVersion
self.databaseType = databaseType
self.languages = languages
self.binaryFormatMajorVersion = majorVersion
self.binaryFormatMinorVersion = minorVersion
self.buildEpoch = buildEpoch
self.description = description
}
init?(_ data: Data) {
guard let iterator = MaxMindIterator(data) else { return nil }
self.init(iterator)
}
}

View File

@ -1,17 +1,49 @@
import Foundation
import MaxMindDecoder
public protocol Metadata {
public struct Metadata {
public let nodeCount: UInt32
public let recordSize: UInt16
public let ipVersion: UInt16
public let databaseType: String
public let languages: [String]
public let binaryFormatMajorVersion: UInt16
public let binaryFormatMinorVersion: UInt16
public let buildEpoch: UInt64
public let description: [String: String]
public var nodeByteSize: UInt16 { get { return recordSize / 4 } }
public var searchTreeSize: UInt64 { get { return UInt64(nodeCount * UInt32(nodeByteSize)) } }
var nodeCount: UInt32 { get }
var recordSize: UInt16 { get }
var ipVersion: UInt16 { get }
var databaseType: String { get }
var languages: [String] { get }
var binaryFormatMajorVersion: UInt16 { get }
var binaryFormatMinorVersion: UInt16 { get }
var buildEpoch: UInt64 { get }
var description: [String:String] { get }
var nodeByteSize: UInt16 { get }
var searchTreeSize: UInt64 { get }
public init?(_ iterator: MaxMindIterator) {
guard let mapControlByte = iterator.next() else { return nil }
if mapControlByte.type != .map { return nil }
let decoder = MaxMindDecoder(inputEndianness: .big)
let decoded: [String: Any] = decoder.decode(iterator, size: Int(mapControlByte.payloadSize))
guard let nodeCount = decoded["node_count"] as? UInt32 else { return nil }
guard let recordSize = decoded["record_size"] as? UInt16 else { return nil }
guard let ipVersion = decoded["ip_version"] as? UInt16 else { return nil }
guard let databaseType = decoded["database_type"] as? String else { return nil }
guard let languages = decoded["languages"] as? [String] else { return nil }
guard let majorVersion = decoded["binary_format_major_version"] as? UInt16 else { return nil }
guard let minorVersion = decoded["binary_format_minor_version"] as? UInt16 else { return nil }
guard let buildEpoch = decoded["build_epoch"] as? UInt64 else { return nil }
guard let description = decoded["description"] as? [String: String] else { return nil }
self.nodeCount = nodeCount
self.recordSize = recordSize
self.ipVersion = ipVersion
self.databaseType = databaseType
self.languages = languages
self.binaryFormatMajorVersion = majorVersion
self.binaryFormatMinorVersion = minorVersion
self.buildEpoch = buildEpoch
self.description = description
}
public init?(_ data: Data) {
guard let iterator = MaxMindIterator(data) else { return nil }
self.init(iterator)
}
}

View File

@ -1,12 +1,12 @@
import Foundation
import XCTest
@testable import MaxMindDBReader
@testable import Metadata
import MaxMindDecoder
class MetadataStructTest: XCTestCase {
class MetadataTest: XCTestCase {
private func assertCalculatedValues(
_ metadata: MetadataStruct,
_ metadata: Metadata,
file: StaticString = #file,
line: UInt = #line
) {
@ -17,21 +17,21 @@ class MetadataStructTest: XCTestCase {
}
func testInit_nilIfCantCreateIterator() {
XCTAssertNil(MetadataStruct(Data()))
XCTAssertNil(Metadata(Data()))
}
func testInit_nilIfCantFetchFirstControlByte() {
let data = Data([0b0000_1111])
XCTAssertNil(MetadataStruct(data))
XCTAssertNil(Metadata(data))
}
func testInit_nilIfFirstControlByteIsNotMap() {
let data = Data([0b0010_1111])
XCTAssertNil(MetadataStruct(data))
XCTAssertNil(Metadata(data))
}
func testInit_withBinary() {
guard let metadata = MetadataStruct(binaryMetaData) else {
guard let metadata = Metadata(binaryMetaData) else {
XCTFail("Input binary is valid. Should have constructed a proper struct.")
return
}
@ -55,7 +55,7 @@ class MetadataStructTest: XCTestCase {
XCTFail("Input binary is valid. Should have constructed a proper MaxMindIterator.")
return
}
guard let metadata = MetadataStruct(iterator) else {
guard let metadata = Metadata(iterator) else {
XCTFail("Input binary is valid. Should have constructed a proper struct.")
return
}