struct JID: Hashable, CustomStringConvertible, Codable, Equatable { let localPart: String let domainPart: String let resourcePart: String? init(_ jid: String) throws { let parts = try JID.parse(jid) localPart = parts.0 domainPart = parts.1 resourcePart = parts.2 } var description: String { var str = "\(localPart)@\(domainPart)" if let resource = resourcePart { str += "/\(resource)" } return str } var hash: Int { if let resourcePart { return "\(localPart)@\(domainPart)/\(resourcePart)".hashValue } else { return "\(localPart)@\(domainPart)".hashValue } } var bare: String { "\(localPart)@\(domainPart)" } var bareHash: Int { "\(localPart)@\(domainPart)".hashValue } } extension JID { var uStr: String { "\(bareHash)".replacingOccurrences(of: "-", with: "_") } } enum JIDError: String, Error { case wrongJid = "Can't parse or operate with JID" } private extension JID { // swiftlint:disable:next large_tuple static func parse(_ str: String) throws -> (String, String, String?) { let parts = str.components(separatedBy: "@") guard parts.count == 2 else { throw JIDError.wrongJid } let secondParts = parts[1].components(separatedBy: "/") guard !secondParts.isEmpty else { throw JIDError.wrongJid } if secondParts.count > 1 { return (parts[0], secondParts[0], secondParts[1]) } else { return (parts[0], secondParts[0], nil) } } }