enum ItemReference { case general case post(Post) case feed case page(Page) case tagPage(Tag) case tagOverview } extension ItemReference: Equatable { } extension ItemReference: Hashable { } extension ItemReference: Identifiable { var id: String { switch self { case .general: return "0-general" case .feed: return "1-feed" case .post(let post): return "2-post-\(post.id)" case .page(let page): return "3-page-\(page.id)" case .tagPage(let tag): return "5-tag-\(tag.id)" case .tagOverview: return "4-tag-overview" } } init?(context: LoadingContext, rawValue: String) { if rawValue == "0-general" { self = .general } else if rawValue == "1-feed" { self = .feed } else if rawValue == "4-tag-overview" { self = .tagOverview } else if let id = rawValue.removingPrefix("3-page-"), let page = context.page(id) { self = .page(page) } else if let id = rawValue.removingPrefix("2-post-"), let post = context.post(id) { self = .post(post) } else if let id = rawValue.removingPrefix("5-tag-"), let tag = context.tag(id) { self = .tagPage(tag) } else { return nil } } } extension ItemReference: Comparable { static func < (lhs: ItemReference, rhs: ItemReference) -> Bool { lhs.id < rhs.id } } extension ItemReference: CustomStringConvertible { var description: String { switch self { case .general: return "General" case .feed: return "Feed" case .post(let post): return "Post \(post.id)" case .page(let page): return "Page \(page.id)" case .tagPage(let tag): return "Tag \(tag.id)" case .tagOverview: return "Tag Overview" } } }