From 5f8bd8b20236b32701a6e7890d9dc9eb778743f7 Mon Sep 17 00:00:00 2001 From: Vegard Matthey Date: Tue, 7 Apr 2026 04:21:04 +0200 Subject: [PATCH] perf: use flatbuffers instead of json for metadata --- .gitignore | 1 + ExportOptions.plist | 2 +- ImageViewer.xcodeproj/project.pbxproj | 42 +- .../xcschemes/ImageViewer.xcscheme | 2 +- ImageViewer/ViewController.swift | 353 ++++++------ ImageViewer/metadata.fbs | 65 +++ ImageViewer/metadata_generated.swift | 532 ++++++++++++++++++ 7 files changed, 800 insertions(+), 197 deletions(-) create mode 100644 ImageViewer/metadata.fbs create mode 100644 ImageViewer/metadata_generated.swift diff --git a/.gitignore b/.gitignore index 3d44dc3..50bd0e8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ buildServer.json .swiftlint.yml /ImageViewer.xcodeproj/xcuserdata /ImageViewer.xcodeproj/project.xcworkspace/xcuserdata +/ImageViewer/flatc diff --git a/ExportOptions.plist b/ExportOptions.plist index 11526e8..1822c54 100644 --- a/ExportOptions.plist +++ b/ExportOptions.plist @@ -4,7 +4,7 @@ method - development + debugging signingStyle automatic destination diff --git a/ImageViewer.xcodeproj/project.pbxproj b/ImageViewer.xcodeproj/project.pbxproj index a54dc11..04a8ec8 100644 --- a/ImageViewer.xcodeproj/project.pbxproj +++ b/ImageViewer.xcodeproj/project.pbxproj @@ -3,16 +3,20 @@ archiveVersion = 1; classes = { }; - objectVersion = 56; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ + 228A32B12F849062008A980A /* metadata_generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228A32B02F849062008A980A /* metadata_generated.swift */; }; + 22B015A72F82A2DC0088F94F /* FlatBuffers in Frameworks */ = {isa = PBXBuildFile; productRef = 22B015A62F82A2DC0088F94F /* FlatBuffers */; }; + 22B015A92F82A2DC0088F94F /* FlexBuffers in Frameworks */ = {isa = PBXBuildFile; productRef = 22B015A82F82A2DC0088F94F /* FlexBuffers */; }; 840F62692E7B65B700C8A64A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840F62682E7B65B700C8A64A /* AppDelegate.swift */; }; 840F626D2E7B65B700C8A64A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840F626C2E7B65B700C8A64A /* ViewController.swift */; }; 840F62722E7B65B900C8A64A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 840F62712E7B65B900C8A64A /* Assets.xcassets */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 228A32B02F849062008A980A /* metadata_generated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = metadata_generated.swift; sourceTree = ""; }; 840F62652E7B65B700C8A64A /* ImageViewer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ImageViewer.app; sourceTree = BUILT_PRODUCTS_DIR; }; 840F62682E7B65B700C8A64A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 840F626C2E7B65B700C8A64A /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -25,6 +29,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 22B015A72F82A2DC0088F94F /* FlatBuffers in Frameworks */, + 22B015A92F82A2DC0088F94F /* FlexBuffers in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -50,6 +56,7 @@ 840F62672E7B65B700C8A64A /* ImageViewer */ = { isa = PBXGroup; children = ( + 228A32B02F849062008A980A /* metadata_generated.swift */, 840F62682E7B65B700C8A64A /* AppDelegate.swift */, 840F626C2E7B65B700C8A64A /* ViewController.swift */, 840F62712E7B65B900C8A64A /* Assets.xcassets */, @@ -86,7 +93,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1420; - LastUpgradeCheck = 1420; + LastUpgradeCheck = 1640; TargetAttributes = { 840F62642E7B65B700C8A64A = { CreatedOnToolsVersion = 14.2; @@ -102,6 +109,9 @@ Base, ); mainGroup = 840F625C2E7B65B700C8A64A; + packageReferences = ( + 22B015A52F82A2DC0088F94F /* XCLocalSwiftPackageReference "../flatbuffers" */, + ); productRefGroup = 840F62662E7B65B700C8A64A /* Products */; projectDirPath = ""; projectRoot = ""; @@ -129,6 +139,7 @@ files = ( 840F626D2E7B65B700C8A64A /* ViewController.swift in Sources */, 840F62692E7B65B700C8A64A /* AppDelegate.swift in Sources */, + 228A32B12F849062008A980A /* metadata_generated.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -169,8 +180,10 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = U5B4RH73LN; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -185,7 +198,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -230,8 +243,10 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = U5B4RH73LN; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -240,7 +255,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -284,7 +299,6 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = U5B4RH73LN; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = ImageViewer/Info.plist; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; @@ -326,6 +340,24 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 22B015A52F82A2DC0088F94F /* XCLocalSwiftPackageReference "../flatbuffers" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = ../flatbuffers; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 22B015A62F82A2DC0088F94F /* FlatBuffers */ = { + isa = XCSwiftPackageProductDependency; + productName = FlatBuffers; + }; + 22B015A82F82A2DC0088F94F /* FlexBuffers */ = { + isa = XCSwiftPackageProductDependency; + productName = FlexBuffers; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 840F625D2E7B65B700C8A64A /* Project object */; } diff --git a/ImageViewer.xcodeproj/xcshareddata/xcschemes/ImageViewer.xcscheme b/ImageViewer.xcodeproj/xcshareddata/xcschemes/ImageViewer.xcscheme index d075589..10a3f56 100644 --- a/ImageViewer.xcodeproj/xcshareddata/xcschemes/ImageViewer.xcscheme +++ b/ImageViewer.xcodeproj/xcshareddata/xcschemes/ImageViewer.xcscheme @@ -1,6 +1,6 @@ 1 ? Int(chapterParts[1])! : nil + let chapter: (UInt32, UInt32?) = ( + UInt32(chapterParts[0])!, chapterParts.count > 1 ? UInt32(chapterParts[1])! : nil ) - let volume = Int((fileName as NSString).substring(with: match.range(at: 2)))! + let volume: UInt32 = UInt32((filename as NSString).substring(with: match.range(at: 2)))! - let pageStr = (fileName as NSString).substring(with: match.range(at: 3)) + let pageStr = (filename as NSString).substring(with: match.range(at: 3)) let pageParts = pageStr.split(separator: "-", maxSplits: 1) let (page, doublePage) = ( - Int(pageParts[0])!, pageParts.count > 1 + UInt32(pageParts[0])!, pageParts.count > 1 ) + + let m_filename = builder.create(string: filename) + let imageMetadata = ImageMetadata.createImageMetadata(&builder, doublePage: doublePage, filenameOffset: m_filename, firstPage: page) if currentVolume != nil { if volume != currentVolume { - newMetadata.chapter_count += 1 assert(volume > currentVolume) - newMetadata.volumes.append( - VolumeMetadata( - volume: MetaValue(main: volume, bonus: nil), name: nil, - chapters: [ - ChapterMetadata( - chapter: MetaValue( - main: chapter.0, bonus: chapter.1 - ), - name: "", - images: [ - ImageMetadata( - doublePage: doublePage, fileName: fileName, - firstPage: page - ), - ] - ), - ] - )) + + let chapterName = builder.create(string: "") + let imagesOffset = builder.createVector(ofOffsets: currentImages) + let chapterMetadata = ChapterMetadata.createChapterMetadata(&builder, + chapter: MetaValue( + main: currentChapter.0, bonus: currentChapter.1 ?? 0 + ), + nameOffset: chapterName, + imagesVectorOffset: imagesOffset, + ) + + currentChapters.append(chapterMetadata) + + let volumeTitle = builder.create(string: "") + let chaptersOffset = builder.createVector(ofOffsets: currentChapters) + let volumeMetadata = VolumeMetadata.createVolumeMetadata( + &builder, + volume: MetaValue(main: volume ?? 0, bonus: 0), + titleOffset: volumeTitle, + chaptersVectorOffset: chaptersOffset + ) + + volumes.append(volumeMetadata) + + currentImages = [imageMetadata] + currentChapters = [] } else if chapter != currentChapter { - newMetadata.chapter_count += 1 if chapter.0 == currentChapter.0 { assert(chapter.1! == currentChapter.1 ?? 1) } else { assert(chapter.0 == currentChapter.0 + 1) } - newMetadata.volumes[newMetadata.volumes.count - 1].chapters.append( - ChapterMetadata( - chapter: MetaValue(main: chapter.0, bonus: chapter.1), - name: "", - images: [ - ImageMetadata( - doublePage: doublePage, fileName: fileName, - firstPage: page - ), - ] - )) - } else { - newMetadata.volumes[newMetadata.volumes.count - 1].chapters[ - newMetadata.volumes[newMetadata.volumes.count - 1].chapters.count - 1 - ].images.append( - ImageMetadata( - doublePage: doublePage, fileName: fileName, firstPage: page - ) + + let chapterName = builder.create(string: "") + let imagesOffset = builder.createVector(ofOffsets: currentImages) + let chapterMetadata = ChapterMetadata.createChapterMetadata(&builder, + chapter: MetaValue( + main: currentChapter.0, bonus: currentChapter.1 ?? 0 + ), + nameOffset: chapterName, + imagesVectorOffset: imagesOffset, ) + + currentChapters.append(chapterMetadata) + + currentImages = [imageMetadata] + + } else { + currentImages.append(imageMetadata) } } else { - newMetadata.chapter_count += 1 - newMetadata.volumes.append( - VolumeMetadata( - volume: MetaValue(main: volume, bonus: nil), name: nil, - chapters: [ - ChapterMetadata( - chapter: MetaValue(main: chapter.0, bonus: chapter.1), - name: "", - images: [ - ImageMetadata( - doublePage: doublePage, fileName: fileName, - firstPage: page - ), - ] - ), - ] - )) + currentImages.append(imageMetadata) + } + if (i == filenames.count - 1) { + currentImages.append(imageMetadata) + + let chapterName = builder.create(string: "") + let imagesOffset = builder.createVector(ofOffsets: currentImages) + let chapterMetadata = ChapterMetadata.createChapterMetadata(&builder, + chapter: MetaValue( + main: chapter.0, bonus: chapter.1 ?? 0 + ), + nameOffset: chapterName, + imagesVectorOffset: imagesOffset, + ) + + currentChapters.append(chapterMetadata) + + let volumeTitle = builder.create(string: "") + let chaptersOffset = builder.createVector(ofOffsets: currentChapters) + let volumeMetadata = VolumeMetadata.createVolumeMetadata( + &builder, + volume: MetaValue(main: volume ?? 0, bonus: 0), + titleOffset: volumeTitle, + chaptersVectorOffset: chaptersOffset + ) + + volumes.append(volumeMetadata) + + currentImages = [] + currentChapters = [] } currentVolume = volume currentChapter = chapter @@ -424,19 +388,31 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { print("failed reading image file names") } - metadata = newMetadata + let title = builder.create(string: "") + let originalLanguage = builder.create(string: "Japanese") + let countryOfOrigin = builder.create(string: "Japan") + let description = builder.create(string: "") + let tags = builder.createVector(ofOffsets: []) + let volumeOffsets = builder.createVector(ofOffsets: volumes) + let metadata = Metadata.createMetadata( + &builder, + titleOffset: title, + format: Format.manga, + originalLanguageOffset: originalLanguage, + countryOfOriginOffset: countryOfOrigin, + publicationDemographic: PublicationDemographic.shounen, + status: Status.finished, + contentRating: ContentRating.safe, + source: Source.original, + startReleaseDate: Date(year: 2000, month: 1, day: 1), + endReleaseDate: Date(year: 2000, month: 1, day: 1), + tagsVectorOffset: tags, + descriptionOffset: description, + volumesVectorOffset: volumeOffsets, + ) - do { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted] - encoder.keyEncodingStrategy = .useDefaultKeys - try encoder.encode( - newMetadata - ).write( - to: path.appendingPathComponent(outFileName)) - } catch { - print("failed to save generated metadata") - } + builder.finish(offset: metadata) + try! builder.data.write(to: path.appendingPathComponent(metadataFilename)) } func saveLocalState() { @@ -480,10 +456,13 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { func loadLocalState() { do { - let json = try Data( - String( - contentsOfFile: currentPath.appendingPathComponent("state.json").path - ).utf8) + let path = currentPath.appendingPathComponent("state.json").path + if !fileManager.fileExists(atPath: path) { + progress = ProgressIndices(v: 0, c: 0, i: 0) + mode = .leftToRight + return + } + let json = try Data(String(contentsOfFile: path).utf8) let local = try JSONDecoder().decode(LocalState.self, from: json) switch local.progress { case let .leftToRight(volumeIndex, chapterIndex, imageIndex): @@ -1067,22 +1046,22 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { return } progress = newProgress - if let path = getImagePath(progress: progress) { + let path = getImagePath(progress: progress) //{ imageLoader.loadImage(at: path, scaling: scaling, screenSize: UIScreen.main.bounds.size) { [weak self] image in self?.imageView.image = image self?.updateInfo() } - } else { - return - } + // } else { + // return + //} for _ in 0 ... preloadCount { newProgress = getProgressIndicesFromTurn(turn: .next, progress: newProgress) - if let path = getImagePath(progress: newProgress) { + let path = getImagePath(progress: newProgress) // { imageLoader.preloadImage(at: path, scaling: scaling, screenSize: UIScreen.main.bounds.size) - } else { - print("could not preload image") - } + // } else { + // print("could not preload image") + //} } saveLocalState() @@ -1090,8 +1069,8 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { func metaValueToString(m: MetaValue) -> String { var r = "" - if let bonus = m.bonus { - r = String(m.main) + "." + String(bonus) + if m.bonus != 0 { + r = String(m.main) + "." + String(m.bonus) } else { r = String(m.main) } @@ -1101,22 +1080,22 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { func updateInfo() { if metadata == nil { return } - var text = "\(metadata.title)\n" + var text = "\(metadata.title ?? "")\n" if let chapterTitle = metadata.volumes[progress.v].chapters[progress.c].name { text += "\(chapterTitle)\n" } - let chapterValue = metadata.volumes[progress.v].chapters[progress.c].chapter + let chapterValue = metadata.volumes[progress.v].chapters[progress.c].chapter! let chapterString = metaValueToString(m: chapterValue) - let lastChapterValue = metadata.last_chapter + let lastChapterValue = metadata.volumes[metadata.volumes.count - 1].chapters[metadata.volumes[metadata.volumes.count - 1].chapters.count - 1].chapter! let lastChapterString = metaValueToString(m: lastChapterValue) - let volumeValue = metadata.volumes[progress.v].volume + let volumeValue = metadata.volumes[progress.v].volume! let volumeString = metaValueToString(m: volumeValue) - let lastVolumeValue = metadata.last_volume + let lastVolumeValue = metadata.volumes[metadata.volumes.count - 1].volume! let lastVolumeString = metaValueToString(m: lastVolumeValue) let lastChapterIndex = metadata.volumes[progress.v].chapters.count - 1 @@ -1153,10 +1132,9 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { info.text = text } - func getImagePath(progress: ProgressIndices) -> URL! { + func getImagePath(progress: ProgressIndices) -> URL { let (v, c, i) = (progress.v, progress.c, progress.i) - let modernPath = currentPath.appendingPathComponent("images").appendingPathComponent( - metadata.volumes[v].chapters[c].images[i].fileName) + let modernPath = currentPath!.appendingPathComponent("images").appendingPathComponent(metadata.volumes[v].chapters[c].images[i].filename) // print("trying to get path \(modernPath)") // if fileManager.fileExists(atPath: modernPath.path) { return modernPath @@ -1199,19 +1177,10 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { } func getMetadata(path: URL) -> Metadata? { - do { - let json = try Data( - String(contentsOfFile: path.appendingPathComponent("metadata.json").path) - .utf8) - let metadata = try JSONDecoder().decode(Metadata.self, from: json) - return metadata - - } catch let decodingError as DecodingError { - print(decodingError.errorDescription!) - } catch { - print("Unexpected error: \(error)") - } - return nil + let data = try! Data(contentsOf: path.appendingPathComponent(metadataFilename)) + var byteBuffer = ByteBuffer(data: data) + let metadata: Metadata = try! getCheckedRoot(byteBuffer: &byteBuffer) + return metadata } func setImages(path _: URL) { @@ -1267,10 +1236,14 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { func getGlobalState() -> GlobalState { let fileManager = FileManager.default if let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first { + let path = documentsURL.appendingPathComponent("state.json").path + if !fileManager.fileExists(atPath: path) { + GlobalState(comicName: nil) + } do { let json = try Data( String( - contentsOfFile: documentsURL.appendingPathComponent("state.json").path + contentsOfFile: path ).utf8) return try JSONDecoder().decode(GlobalState.self, from: json) } catch { @@ -1368,7 +1341,7 @@ extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFl if collectionView == comicCollectionView { let selectedComic = comics[indexPath.item] - readComic(name: selectedComic.metadata.title) + readComic(name: selectedComic.metadata.title!) } } } diff --git a/ImageViewer/metadata.fbs b/ImageViewer/metadata.fbs new file mode 100644 index 0000000..099d372 --- /dev/null +++ b/ImageViewer/metadata.fbs @@ -0,0 +1,65 @@ +enum Format:byte { Manga, Novel, OneShot } +enum Status:byte { Finished, Releasing, Hiatus, NotYetReleased, Cancelled } +enum PublicationDemographic:byte { Shounen, Shoujou, Seinen, Josei } +enum Source:byte { Original, Manga, LightNovel, VisualNovel, VideoGame, Other, Novel, Doujinshi, Anime, WebNovel, LiveAction, Game, Comic, MultimediaProject, PictureBook } +enum ContentRating:byte { Safe, Suggestive, Erotica, Pornographic } + +enum TagType:byte { Format, Genre, Theme, Content } + +table Tag { + type:TagType; + value:string; +} + +struct MetaValue { + main:uint; + bonus:uint; +} + +struct Date { + year:ushort; + month:ubyte; + day:ubyte; +} + +struct Size { + width:uint; + height:uint; +} + +table ImageMetadata { + double_page:bool; + filename:string (required); + first_page:uint; + size:Size; +} + +table ChapterMetadata { + chapter:MetaValue; + name:string; + images:[ImageMetadata]; +} + +table VolumeMetadata { + volume:MetaValue; + title:string; + chapters:[ChapterMetadata]; +} + +table Metadata { + title:string (required); + format:Format; + original_language:string; + country_of_origin:string; + publication_demographic:PublicationDemographic; + status:Status; + content_rating:ContentRating; + source:Source; + start_release_date:Date; + end_release_date:Date; + tags:[Tag]; + description:string; + volumes:[VolumeMetadata]; +} + +root_type Metadata; diff --git a/ImageViewer/metadata_generated.swift b/ImageViewer/metadata_generated.swift new file mode 100644 index 0000000..8964f6a --- /dev/null +++ b/ImageViewer/metadata_generated.swift @@ -0,0 +1,532 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// swiftlint:disable all +// swiftformat:disable all + +#if canImport(Common) +import Common +#endif + +import FlatBuffers + +public enum Format: Int8, FlatbuffersVectorInitializable, Enum, Verifiable { + public typealias T = Int8 + public static var byteSize: Int { return MemoryLayout.size } + public var value: Int8 { return self.rawValue } + case manga = 0 + case novel = 1 + case oneshot = 2 + + public static var max: Format { return .oneshot } + public static var min: Format { return .manga } +} + + +public enum Status: Int8, FlatbuffersVectorInitializable, Enum, Verifiable { + public typealias T = Int8 + public static var byteSize: Int { return MemoryLayout.size } + public var value: Int8 { return self.rawValue } + case finished = 0 + case releasing = 1 + case hiatus = 2 + case notyetreleased = 3 + case cancelled = 4 + + public static var max: Status { return .cancelled } + public static var min: Status { return .finished } +} + + +public enum PublicationDemographic: Int8, FlatbuffersVectorInitializable, Enum, Verifiable { + public typealias T = Int8 + public static var byteSize: Int { return MemoryLayout.size } + public var value: Int8 { return self.rawValue } + case shounen = 0 + case shoujou = 1 + case seinen = 2 + case josei = 3 + + public static var max: PublicationDemographic { return .josei } + public static var min: PublicationDemographic { return .shounen } +} + + +public enum Source: Int8, FlatbuffersVectorInitializable, Enum, Verifiable { + public typealias T = Int8 + public static var byteSize: Int { return MemoryLayout.size } + public var value: Int8 { return self.rawValue } + case original = 0 + case manga = 1 + case lightnovel = 2 + case visualnovel = 3 + case videogame = 4 + case other = 5 + case novel = 6 + case doujinshi = 7 + case anime = 8 + case webnovel = 9 + case liveaction = 10 + case game = 11 + case comic = 12 + case multimediaproject = 13 + case picturebook = 14 + + public static var max: Source { return .picturebook } + public static var min: Source { return .original } +} + + +public enum ContentRating: Int8, FlatbuffersVectorInitializable, Enum, Verifiable { + public typealias T = Int8 + public static var byteSize: Int { return MemoryLayout.size } + public var value: Int8 { return self.rawValue } + case safe = 0 + case suggestive = 1 + case erotica = 2 + case pornographic = 3 + + public static var max: ContentRating { return .pornographic } + public static var min: ContentRating { return .safe } +} + + +public enum TagType: Int8, FlatbuffersVectorInitializable, Enum, Verifiable { + public typealias T = Int8 + public static var byteSize: Int { return MemoryLayout.size } + public var value: Int8 { return self.rawValue } + case format = 0 + case genre = 1 + case theme = 2 + case content = 3 + + public static var max: TagType { return .content } + public static var min: TagType { return .format } +} + + +public struct MetaValue: NativeStruct, FlatbuffersVectorInitializable, Verifiable, FlatbuffersInitializable { + + static func validateVersion() { FlatBuffersVersion_25_12_19() } + + private var _main: UInt32 + private var _bonus: UInt32 + + public init(_ bb: ByteBuffer, o: Int32) { + self = bb.read(def: Self.self, position: Int(o)) + } + + public init(main: UInt32, bonus: UInt32) { + _main = main + _bonus = bonus + } + + public init() { + _main = 0 + _bonus = 0 + } + + public var main: UInt32 { _main } + public var bonus: UInt32 { _bonus } + + public static func verify(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + try verifier.inBuffer(position: position, of: MetaValue.self) + } +} + +public struct MetaValue_Mutable: FlatBufferStruct, FlatbuffersVectorInitializable { + + static func validateVersion() { FlatBuffersVersion_25_12_19() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Struct + + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) } + + public var main: UInt32 { return _accessor.readBuffer(of: UInt32.self, at: 0) } + public var bonus: UInt32 { return _accessor.readBuffer(of: UInt32.self, at: 4) } +} + +public struct Date: NativeStruct, FlatbuffersVectorInitializable, Verifiable, FlatbuffersInitializable { + + static func validateVersion() { FlatBuffersVersion_25_12_19() } + + private var _year: UInt16 + private var _month: UInt8 + private var _day: UInt8 + + public init(_ bb: ByteBuffer, o: Int32) { + self = bb.read(def: Self.self, position: Int(o)) + } + + public init(year: UInt16, month: UInt8, day: UInt8) { + _year = year + _month = month + _day = day + } + + public init() { + _year = 0 + _month = 0 + _day = 0 + } + + public var year: UInt16 { _year } + public var month: UInt8 { _month } + public var day: UInt8 { _day } + + public static func verify(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + try verifier.inBuffer(position: position, of: Date.self) + } +} + +public struct Date_Mutable: FlatBufferStruct, FlatbuffersVectorInitializable { + + static func validateVersion() { FlatBuffersVersion_25_12_19() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Struct + + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) } + + public var year: UInt16 { return _accessor.readBuffer(of: UInt16.self, at: 0) } + public var month: UInt8 { return _accessor.readBuffer(of: UInt8.self, at: 2) } + public var day: UInt8 { return _accessor.readBuffer(of: UInt8.self, at: 3) } +} + +public struct Size: NativeStruct, FlatbuffersVectorInitializable, Verifiable, FlatbuffersInitializable { + + static func validateVersion() { FlatBuffersVersion_25_12_19() } + + private var _width: UInt32 + private var _height: UInt32 + + public init(_ bb: ByteBuffer, o: Int32) { + self = bb.read(def: Self.self, position: Int(o)) + } + + public init(width: UInt32, height: UInt32) { + _width = width + _height = height + } + + public init() { + _width = 0 + _height = 0 + } + + public var width: UInt32 { _width } + public var height: UInt32 { _height } + + public static func verify(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + try verifier.inBuffer(position: position, of: Size.self) + } +} + +public struct Size_Mutable: FlatBufferStruct, FlatbuffersVectorInitializable { + + static func validateVersion() { FlatBuffersVersion_25_12_19() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Struct + + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) } + + public var width: UInt32 { return _accessor.readBuffer(of: UInt32.self, at: 0) } + public var height: UInt32 { return _accessor.readBuffer(of: UInt32.self, at: 4) } +} + +public struct Tag: FlatBufferTable, FlatbuffersVectorInitializable, Verifiable { + + static func validateVersion() { FlatBuffersVersion_25_12_19() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Table + + private init(_ t: Table) { _accessor = t } + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) } + + private struct VT { + static let type: VOffset = 4 + static let value: VOffset = 6 + } + + public var type: TagType { let o = _accessor.offset(VT.type); return o == 0 ? .format : TagType(rawValue: _accessor.readBuffer(of: Int8.self, at: o)) ?? .format } + public var value: String? { let o = _accessor.offset(VT.value); return o == 0 ? nil : _accessor.string(at: o) } + public var valueSegmentArray: [UInt8]? { return _accessor.getVector(at: VT.value) } + public static func startTag(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 2) } + public static func add(type: TagType, _ fbb: inout FlatBufferBuilder) { fbb.add(element: type.rawValue, def: 0, at: VT.type) } + public static func add(value: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: value, at: VT.value) } + public static func endTag(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end } + public static func createTag( + _ fbb: inout FlatBufferBuilder, + type: TagType = .format, + valueOffset value: Offset = Offset() + ) -> Offset { + let __start = Tag.startTag(&fbb) + Tag.add(type: type, &fbb) + Tag.add(value: value, &fbb) + return Tag.endTag(&fbb, start: __start) + } + + public static func verify(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VT.type, fieldName: "type", required: false, type: TagType.self) + try _v.visit(field: VT.value, fieldName: "value", required: false, type: ForwardOffset.self) + _v.finish() + } +} + +public struct ImageMetadata: FlatBufferTable, FlatbuffersVectorInitializable, Verifiable { + + static func validateVersion() { FlatBuffersVersion_25_12_19() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Table + + private init(_ t: Table) { _accessor = t } + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) } + + private struct VT { + static let doublePage: VOffset = 4 + static let filename: VOffset = 6 + static let firstPage: VOffset = 8 + static let size: VOffset = 10 + } + + public var doublePage: Bool { let o = _accessor.offset(VT.doublePage); return o == 0 ? false : _accessor.readBuffer(of: Bool.self, at: o) } + public var filename: String! { let o = _accessor.offset(VT.filename); return _accessor.string(at: o) } + public var filenameSegmentArray: [UInt8]! { return _accessor.getVector(at: VT.filename) } + public var firstPage: UInt32 { let o = _accessor.offset(VT.firstPage); return o == 0 ? 0 : _accessor.readBuffer(of: UInt32.self, at: o) } + public var size: Size? { let o = _accessor.offset(VT.size); return o == 0 ? nil : _accessor.readBuffer(of: Size.self, at: o) } + public var mutableSize: Size_Mutable? { let o = _accessor.offset(VT.size); return o == 0 ? nil : Size_Mutable(_accessor.bb, o: o + _accessor.position) } + public static func startImageMetadata(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 4) } + public static func add(doublePage: Bool, _ fbb: inout FlatBufferBuilder) { fbb.add(element: doublePage, def: false, + at: VT.doublePage) } + public static func add(filename: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: filename, at: VT.filename) } + public static func add(firstPage: UInt32, _ fbb: inout FlatBufferBuilder) { fbb.add(element: firstPage, def: 0, at: VT.firstPage) } + public static func add(size: Size?, _ fbb: inout FlatBufferBuilder) { guard let size = size else { return }; fbb.create(struct: size, position: VT.size) } + public static func endImageMetadata(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); fbb.require(table: end, fields: [6]); return end } + public static func createImageMetadata( + _ fbb: inout FlatBufferBuilder, + doublePage: Bool = false, + filenameOffset filename: Offset, + firstPage: UInt32 = 0, + size: Size? = nil + ) -> Offset { + let __start = ImageMetadata.startImageMetadata(&fbb) + ImageMetadata.add(doublePage: doublePage, &fbb) + ImageMetadata.add(filename: filename, &fbb) + ImageMetadata.add(firstPage: firstPage, &fbb) + ImageMetadata.add(size: size, &fbb) + return ImageMetadata.endImageMetadata(&fbb, start: __start) + } + + public static func verify(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VT.doublePage, fieldName: "doublePage", required: false, type: Bool.self) + try _v.visit(field: VT.filename, fieldName: "filename", required: true, type: ForwardOffset.self) + try _v.visit(field: VT.firstPage, fieldName: "firstPage", required: false, type: UInt32.self) + try _v.visit(field: VT.size, fieldName: "size", required: false, type: Size.self) + _v.finish() + } +} + +public struct ChapterMetadata: FlatBufferTable, FlatbuffersVectorInitializable, Verifiable { + + static func validateVersion() { FlatBuffersVersion_25_12_19() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Table + + private init(_ t: Table) { _accessor = t } + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) } + + private struct VT { + static let chapter: VOffset = 4 + static let name: VOffset = 6 + static let images: VOffset = 8 + } + + public var chapter: MetaValue? { let o = _accessor.offset(VT.chapter); return o == 0 ? nil : _accessor.readBuffer(of: MetaValue.self, at: o) } + public var mutableChapter: MetaValue_Mutable? { let o = _accessor.offset(VT.chapter); return o == 0 ? nil : MetaValue_Mutable(_accessor.bb, o: o + _accessor.position) } + public var name: String? { let o = _accessor.offset(VT.name); return o == 0 ? nil : _accessor.string(at: o) } + public var nameSegmentArray: [UInt8]? { return _accessor.getVector(at: VT.name) } + public var images: FlatbufferVector { return _accessor.vector(at: VT.images, byteSize: 4) } + public static func startChapterMetadata(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 3) } + public static func add(chapter: MetaValue?, _ fbb: inout FlatBufferBuilder) { guard let chapter = chapter else { return }; fbb.create(struct: chapter, position: VT.chapter) } + public static func add(name: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: name, at: VT.name) } + public static func addVectorOf(images: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: images, at: VT.images) } + public static func endChapterMetadata(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end } + public static func createChapterMetadata( + _ fbb: inout FlatBufferBuilder, + chapter: MetaValue? = nil, + nameOffset name: Offset = Offset(), + imagesVectorOffset images: Offset = Offset() + ) -> Offset { + let __start = ChapterMetadata.startChapterMetadata(&fbb) + ChapterMetadata.add(chapter: chapter, &fbb) + ChapterMetadata.add(name: name, &fbb) + ChapterMetadata.addVectorOf(images: images, &fbb) + return ChapterMetadata.endChapterMetadata(&fbb, start: __start) + } + + public static func verify(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VT.chapter, fieldName: "chapter", required: false, type: MetaValue.self) + try _v.visit(field: VT.name, fieldName: "name", required: false, type: ForwardOffset.self) + try _v.visit(field: VT.images, fieldName: "images", required: false, type: ForwardOffset, ImageMetadata>>.self) + _v.finish() + } +} + +public struct VolumeMetadata: FlatBufferTable, FlatbuffersVectorInitializable, Verifiable { + + static func validateVersion() { FlatBuffersVersion_25_12_19() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Table + + private init(_ t: Table) { _accessor = t } + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) } + + private struct VT { + static let volume: VOffset = 4 + static let title: VOffset = 6 + static let chapters: VOffset = 8 + } + + public var volume: MetaValue? { let o = _accessor.offset(VT.volume); return o == 0 ? nil : _accessor.readBuffer(of: MetaValue.self, at: o) } + public var mutableVolume: MetaValue_Mutable? { let o = _accessor.offset(VT.volume); return o == 0 ? nil : MetaValue_Mutable(_accessor.bb, o: o + _accessor.position) } + public var title: String? { let o = _accessor.offset(VT.title); return o == 0 ? nil : _accessor.string(at: o) } + public var titleSegmentArray: [UInt8]? { return _accessor.getVector(at: VT.title) } + public var chapters: FlatbufferVector { return _accessor.vector(at: VT.chapters, byteSize: 4) } + public static func startVolumeMetadata(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 3) } + public static func add(volume: MetaValue?, _ fbb: inout FlatBufferBuilder) { guard let volume = volume else { return }; fbb.create(struct: volume, position: VT.volume) } + public static func add(title: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: title, at: VT.title) } + public static func addVectorOf(chapters: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: chapters, at: VT.chapters) } + public static func endVolumeMetadata(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end } + public static func createVolumeMetadata( + _ fbb: inout FlatBufferBuilder, + volume: MetaValue? = nil, + titleOffset title: Offset = Offset(), + chaptersVectorOffset chapters: Offset = Offset() + ) -> Offset { + let __start = VolumeMetadata.startVolumeMetadata(&fbb) + VolumeMetadata.add(volume: volume, &fbb) + VolumeMetadata.add(title: title, &fbb) + VolumeMetadata.addVectorOf(chapters: chapters, &fbb) + return VolumeMetadata.endVolumeMetadata(&fbb, start: __start) + } + + public static func verify(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VT.volume, fieldName: "volume", required: false, type: MetaValue.self) + try _v.visit(field: VT.title, fieldName: "title", required: false, type: ForwardOffset.self) + try _v.visit(field: VT.chapters, fieldName: "chapters", required: false, type: ForwardOffset, ChapterMetadata>>.self) + _v.finish() + } +} + +public struct Metadata: FlatBufferTable, FlatbuffersVectorInitializable, Verifiable { + + static func validateVersion() { FlatBuffersVersion_25_12_19() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Table + + private init(_ t: Table) { _accessor = t } + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) } + + private struct VT { + static let title: VOffset = 4 + static let format: VOffset = 6 + static let originalLanguage: VOffset = 8 + static let countryOfOrigin: VOffset = 10 + static let publicationDemographic: VOffset = 12 + static let status: VOffset = 14 + static let contentRating: VOffset = 16 + static let source: VOffset = 18 + static let startReleaseDate: VOffset = 20 + static let endReleaseDate: VOffset = 22 + static let tags: VOffset = 24 + static let description: VOffset = 26 + static let volumes: VOffset = 28 + } + + public var title: String! { let o = _accessor.offset(VT.title); return _accessor.string(at: o) } + public var titleSegmentArray: [UInt8]! { return _accessor.getVector(at: VT.title) } + public var format: Format { let o = _accessor.offset(VT.format); return o == 0 ? .manga : Format(rawValue: _accessor.readBuffer(of: Int8.self, at: o)) ?? .manga } + public var originalLanguage: String? { let o = _accessor.offset(VT.originalLanguage); return o == 0 ? nil : _accessor.string(at: o) } + public var originalLanguageSegmentArray: [UInt8]? { return _accessor.getVector(at: VT.originalLanguage) } + public var countryOfOrigin: String? { let o = _accessor.offset(VT.countryOfOrigin); return o == 0 ? nil : _accessor.string(at: o) } + public var countryOfOriginSegmentArray: [UInt8]? { return _accessor.getVector(at: VT.countryOfOrigin) } + public var publicationDemographic: PublicationDemographic { let o = _accessor.offset(VT.publicationDemographic); return o == 0 ? .shounen : PublicationDemographic(rawValue: _accessor.readBuffer(of: Int8.self, at: o)) ?? .shounen } + public var status: Status { let o = _accessor.offset(VT.status); return o == 0 ? .finished : Status(rawValue: _accessor.readBuffer(of: Int8.self, at: o)) ?? .finished } + public var contentRating: ContentRating { let o = _accessor.offset(VT.contentRating); return o == 0 ? .safe : ContentRating(rawValue: _accessor.readBuffer(of: Int8.self, at: o)) ?? .safe } + public var source: Source { let o = _accessor.offset(VT.source); return o == 0 ? .original : Source(rawValue: _accessor.readBuffer(of: Int8.self, at: o)) ?? .original } + public var startReleaseDate: Date? { let o = _accessor.offset(VT.startReleaseDate); return o == 0 ? nil : _accessor.readBuffer(of: Date.self, at: o) } + public var mutableStartReleaseDate: Date_Mutable? { let o = _accessor.offset(VT.startReleaseDate); return o == 0 ? nil : Date_Mutable(_accessor.bb, o: o + _accessor.position) } + public var endReleaseDate: Date? { let o = _accessor.offset(VT.endReleaseDate); return o == 0 ? nil : _accessor.readBuffer(of: Date.self, at: o) } + public var mutableEndReleaseDate: Date_Mutable? { let o = _accessor.offset(VT.endReleaseDate); return o == 0 ? nil : Date_Mutable(_accessor.bb, o: o + _accessor.position) } + public var tags: FlatbufferVector { return _accessor.vector(at: VT.tags, byteSize: 4) } + public var description: String? { let o = _accessor.offset(VT.description); return o == 0 ? nil : _accessor.string(at: o) } + public var descriptionSegmentArray: [UInt8]? { return _accessor.getVector(at: VT.description) } + public var volumes: FlatbufferVector { return _accessor.vector(at: VT.volumes, byteSize: 4) } + public static func startMetadata(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 13) } + public static func add(title: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: title, at: VT.title) } + public static func add(format: Format, _ fbb: inout FlatBufferBuilder) { fbb.add(element: format.rawValue, def: 0, at: VT.format) } + public static func add(originalLanguage: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: originalLanguage, at: VT.originalLanguage) } + public static func add(countryOfOrigin: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: countryOfOrigin, at: VT.countryOfOrigin) } + public static func add(publicationDemographic: PublicationDemographic, _ fbb: inout FlatBufferBuilder) { fbb.add(element: publicationDemographic.rawValue, def: 0, at: VT.publicationDemographic) } + public static func add(status: Status, _ fbb: inout FlatBufferBuilder) { fbb.add(element: status.rawValue, def: 0, at: VT.status) } + public static func add(contentRating: ContentRating, _ fbb: inout FlatBufferBuilder) { fbb.add(element: contentRating.rawValue, def: 0, at: VT.contentRating) } + public static func add(source: Source, _ fbb: inout FlatBufferBuilder) { fbb.add(element: source.rawValue, def: 0, at: VT.source) } + public static func add(startReleaseDate: Date?, _ fbb: inout FlatBufferBuilder) { guard let startReleaseDate = startReleaseDate else { return }; fbb.create(struct: startReleaseDate, position: VT.startReleaseDate) } + public static func add(endReleaseDate: Date?, _ fbb: inout FlatBufferBuilder) { guard let endReleaseDate = endReleaseDate else { return }; fbb.create(struct: endReleaseDate, position: VT.endReleaseDate) } + public static func addVectorOf(tags: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: tags, at: VT.tags) } + public static func add(description: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: description, at: VT.description) } + public static func addVectorOf(volumes: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: volumes, at: VT.volumes) } + public static func endMetadata(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); fbb.require(table: end, fields: [4]); return end } + public static func createMetadata( + _ fbb: inout FlatBufferBuilder, + titleOffset title: Offset, + format: Format = .manga, + originalLanguageOffset originalLanguage: Offset = Offset(), + countryOfOriginOffset countryOfOrigin: Offset = Offset(), + publicationDemographic: PublicationDemographic = .shounen, + status: Status = .finished, + contentRating: ContentRating = .safe, + source: Source = .original, + startReleaseDate: Date? = nil, + endReleaseDate: Date? = nil, + tagsVectorOffset tags: Offset = Offset(), + descriptionOffset description: Offset = Offset(), + volumesVectorOffset volumes: Offset = Offset() + ) -> Offset { + let __start = Metadata.startMetadata(&fbb) + Metadata.add(title: title, &fbb) + Metadata.add(format: format, &fbb) + Metadata.add(originalLanguage: originalLanguage, &fbb) + Metadata.add(countryOfOrigin: countryOfOrigin, &fbb) + Metadata.add(publicationDemographic: publicationDemographic, &fbb) + Metadata.add(status: status, &fbb) + Metadata.add(contentRating: contentRating, &fbb) + Metadata.add(source: source, &fbb) + Metadata.add(startReleaseDate: startReleaseDate, &fbb) + Metadata.add(endReleaseDate: endReleaseDate, &fbb) + Metadata.addVectorOf(tags: tags, &fbb) + Metadata.add(description: description, &fbb) + Metadata.addVectorOf(volumes: volumes, &fbb) + return Metadata.endMetadata(&fbb, start: __start) + } + + public static func verify(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VT.title, fieldName: "title", required: true, type: ForwardOffset.self) + try _v.visit(field: VT.format, fieldName: "format", required: false, type: Format.self) + try _v.visit(field: VT.originalLanguage, fieldName: "originalLanguage", required: false, type: ForwardOffset.self) + try _v.visit(field: VT.countryOfOrigin, fieldName: "countryOfOrigin", required: false, type: ForwardOffset.self) + try _v.visit(field: VT.publicationDemographic, fieldName: "publicationDemographic", required: false, type: PublicationDemographic.self) + try _v.visit(field: VT.status, fieldName: "status", required: false, type: Status.self) + try _v.visit(field: VT.contentRating, fieldName: "contentRating", required: false, type: ContentRating.self) + try _v.visit(field: VT.source, fieldName: "source", required: false, type: Source.self) + try _v.visit(field: VT.startReleaseDate, fieldName: "startReleaseDate", required: false, type: Date.self) + try _v.visit(field: VT.endReleaseDate, fieldName: "endReleaseDate", required: false, type: Date.self) + try _v.visit(field: VT.tags, fieldName: "tags", required: false, type: ForwardOffset, Tag>>.self) + try _v.visit(field: VT.description, fieldName: "description", required: false, type: ForwardOffset.self) + try _v.visit(field: VT.volumes, fieldName: "volumes", required: false, type: ForwardOffset, VolumeMetadata>>.self) + _v.finish() + } +} +