import Foundation public struct RDEPUBCFIRange: Codable, Equatable, Hashable { public var parent: RDEPUBCFI? public var start: RDEPUBCFI public var end: RDEPUBCFI /// Always computed from components — no stale cached value risk. public var rawValue: String { RDEPUBCFISerializer.serializeRange(self) } /// Initialize from components. The `rawValue` parameter is ignored — rawValue is always /// computed from the components. To parse a CFI range string, use `RDEPUBCFIParser.parseRange(_:)`. public init(rawValue: String = "", parent: RDEPUBCFI? = nil, start: RDEPUBCFI, end: RDEPUBCFI) { self.parent = parent self.start = start self.end = end } public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() let rawValue = try container.decode(String.self) let parsed = try RDEPUBCFIParser.parseRange(rawValue) self.parent = parsed.parent self.start = parsed.start self.end = parsed.end } public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() try container.encode(rawValue) } }