diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/Bremer.xcodeproj/project.pbxproj b/Bremer.xcodeproj/project.pbxproj new file mode 100644 index 0000000..ab10689 --- /dev/null +++ b/Bremer.xcodeproj/project.pbxproj @@ -0,0 +1,576 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 38006C412A7E3FCC0027A05C /* ApiModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38006C402A7E3FCC0027A05C /* ApiModel.swift */; }; + 38006C432A7E42240027A05C /* AudioPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38006C422A7E42240027A05C /* AudioPlayerView.swift */; }; + 38006C452A7FEE640027A05C /* TagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38006C442A7FEE640027A05C /* TagView.swift */; }; + 38006C4A2A81F5770027A05C /* AllPlaylistViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38006C492A81F5770027A05C /* AllPlaylistViewModel.swift */; }; + 382AB9602A8BBC5A00928393 /* ToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382AB95F2A8BBC5A00928393 /* ToastView.swift */; }; + 382AB9622A90DC4300928393 /* LatestRecentlyPlayedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382AB9612A90DC4300928393 /* LatestRecentlyPlayedView.swift */; }; + 382AB9662A93B88800928393 /* PlaylistAudioViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382AB9652A93B88800928393 /* PlaylistAudioViewModel.swift */; }; + 382AB9682A93B8F300928393 /* TagAudioViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382AB9672A93B8F300928393 /* TagAudioViewModel.swift */; }; + 382AB96A2A93B93F00928393 /* SearchAudioViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382AB9692A93B93F00928393 /* SearchAudioViewModel.swift */; }; + 382AB96C2A93B95900928393 /* LatestRecentlyPlayedAudioViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382AB96B2A93B95900928393 /* LatestRecentlyPlayedAudioViewModel.swift */; }; + 382AB9702A93B9D900928393 /* LocalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382AB96F2A93B9D900928393 /* LocalView.swift */; }; + 382AB9742A964D5A00928393 /* AllTagsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382AB9732A964D5A00928393 /* AllTagsViewModel.swift */; }; + 38317EDA2AA8BA15003193B7 /* NameAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38317ED92AA8BA15003193B7 /* NameAlertView.swift */; }; + 38317EDD2AAC12C0003193B7 /* RenameAudioView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38317EDC2AAC12C0003193B7 /* RenameAudioView.swift */; }; + 38317EDF2AAC6D55003193B7 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38317EDE2AAC6D55003193B7 /* Error.swift */; }; + 383999AD2A065DD3005DAB56 /* BremerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383999AC2A065DD3005DAB56 /* BremerApp.swift */; }; + 383999AF2A065DD3005DAB56 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383999AE2A065DD3005DAB56 /* ContentView.swift */; }; + 383999B12A065DD4005DAB56 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 383999B02A065DD4005DAB56 /* Assets.xcassets */; }; + 383999B42A065DD4005DAB56 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 383999B32A065DD4005DAB56 /* Preview Assets.xcassets */; }; + 3847F01D2A64117900DDB350 /* AudioPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3847F01C2A64117900DDB350 /* AudioPlayerViewModel.swift */; }; + 3847F0212A6447C700DDB350 /* PlaylistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3847F0202A6447C700DDB350 /* PlaylistView.swift */; }; + 3847F0232A64FAA900DDB350 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3847F0222A64FAA900DDB350 /* SearchView.swift */; }; + 3847F0252A6501FC00DDB350 /* BremerApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3847F0242A6501FC00DDB350 /* BremerApi.swift */; }; + 3847F0292A6C121100DDB350 /* LoginButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3847F0282A6C121100DDB350 /* LoginButton.swift */; }; + 38ECE1D12A4B31110044E913 /* LoginWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38ECE1D02A4B31110044E913 /* LoginWebView.swift */; }; + 38FB93612A9A16FA00967B01 /* SettingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FB93602A9A16FA00967B01 /* SettingViewModel.swift */; }; + 38FB93632A9A257C00967B01 /* SettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FB93622A9A257C00967B01 /* SettingView.swift */; }; + 38FB93672AA2DCA400967B01 /* SearchDetailAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FB93662AA2DCA400967B01 /* SearchDetailAlertView.swift */; }; + 38FB936F2AA2DE5D00967B01 /* RenameAudioAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FB936E2AA2DE5D00967B01 /* RenameAudioAlertView.swift */; }; + 5DA23E753A5913DC36665E82 /* Pods_Bremer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9ABE7FFD426EF8354B37CD27 /* Pods_Bremer.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 176731527F753820AF2F9A4D /* Pods-BremerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BremerTests.release.xcconfig"; path = "Target Support Files/Pods-BremerTests/Pods-BremerTests.release.xcconfig"; sourceTree = ""; }; + 38006C402A7E3FCC0027A05C /* ApiModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiModel.swift; sourceTree = ""; }; + 38006C422A7E42240027A05C /* AudioPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayerView.swift; sourceTree = ""; }; + 38006C442A7FEE640027A05C /* TagView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagView.swift; sourceTree = ""; }; + 38006C492A81F5770027A05C /* AllPlaylistViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllPlaylistViewModel.swift; sourceTree = ""; }; + 382AB95F2A8BBC5A00928393 /* ToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastView.swift; sourceTree = ""; }; + 382AB9612A90DC4300928393 /* LatestRecentlyPlayedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestRecentlyPlayedView.swift; sourceTree = ""; }; + 382AB9652A93B88800928393 /* PlaylistAudioViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistAudioViewModel.swift; sourceTree = ""; }; + 382AB9672A93B8F300928393 /* TagAudioViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagAudioViewModel.swift; sourceTree = ""; }; + 382AB9692A93B93F00928393 /* SearchAudioViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchAudioViewModel.swift; sourceTree = ""; }; + 382AB96B2A93B95900928393 /* LatestRecentlyPlayedAudioViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestRecentlyPlayedAudioViewModel.swift; sourceTree = ""; }; + 382AB96F2A93B9D900928393 /* LocalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalView.swift; sourceTree = ""; }; + 382AB9732A964D5A00928393 /* AllTagsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllTagsViewModel.swift; sourceTree = ""; }; + 382AB9762A99FD8D00928393 /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; name = Cartfile; path = BremerApp/Cartfile; sourceTree = ""; }; + 382AB9772A9A00E800928393 /* RealmSwift */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RealmSwift; path = "BremerApp/Carthage/Checkouts/realm-cocoa/RealmSwift"; sourceTree = ""; }; + 382AB9782A9A00E800928393 /* Realm */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Realm; path = "BremerApp/Carthage/Checkouts/realm-cocoa/Realm"; sourceTree = ""; }; + 38317ED92AA8BA15003193B7 /* NameAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NameAlertView.swift; sourceTree = ""; }; + 38317EDC2AAC12C0003193B7 /* RenameAudioView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenameAudioView.swift; sourceTree = ""; }; + 38317EDE2AAC6D55003193B7 /* Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = ""; }; + 383999A92A065DD3005DAB56 /* Bremer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Bremer.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 383999AC2A065DD3005DAB56 /* BremerApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BremerApp.swift; sourceTree = ""; }; + 383999AE2A065DD3005DAB56 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 383999B02A065DD4005DAB56 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 383999B32A065DD4005DAB56 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 3847F01C2A64117900DDB350 /* AudioPlayerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayerViewModel.swift; sourceTree = ""; }; + 3847F0202A6447C700DDB350 /* PlaylistView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistView.swift; sourceTree = ""; }; + 3847F0222A64FAA900DDB350 /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = ""; }; + 3847F0242A6501FC00DDB350 /* BremerApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BremerApi.swift; sourceTree = ""; }; + 3847F0282A6C121100DDB350 /* LoginButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginButton.swift; sourceTree = ""; }; + 3883C6EC2A0A88280059FE42 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 38ECE1D02A4B31110044E913 /* LoginWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginWebView.swift; sourceTree = ""; }; + 38FB93602A9A16FA00967B01 /* SettingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingViewModel.swift; sourceTree = ""; }; + 38FB93622A9A257C00967B01 /* SettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingView.swift; sourceTree = ""; }; + 38FB93662AA2DCA400967B01 /* SearchDetailAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailAlertView.swift; sourceTree = ""; }; + 38FB936E2AA2DE5D00967B01 /* RenameAudioAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenameAudioAlertView.swift; sourceTree = ""; }; + 70A47812EFF9D6BB89E5CF8A /* Pods_BremerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BremerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 74CD6B89272147713072414F /* Pods_Bremer_BremerUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Bremer_BremerUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9ABE7FFD426EF8354B37CD27 /* Pods_Bremer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Bremer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9EFB19BFE75A26E2FB4FFDF4 /* Pods-BremerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BremerTests.debug.xcconfig"; path = "Target Support Files/Pods-BremerTests/Pods-BremerTests.debug.xcconfig"; sourceTree = ""; }; + BB5810515AC8560C0B62517E /* Pods-Bremer-BremerUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Bremer-BremerUITests.debug.xcconfig"; path = "Target Support Files/Pods-Bremer-BremerUITests/Pods-Bremer-BremerUITests.debug.xcconfig"; sourceTree = ""; }; + F0DD7A4E777DA2CCA7D3A5FF /* Pods-Bremer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Bremer.debug.xcconfig"; path = "Target Support Files/Pods-Bremer/Pods-Bremer.debug.xcconfig"; sourceTree = ""; }; + F38464A7DA34FCACEC507C2B /* Pods-Bremer-BremerUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Bremer-BremerUITests.release.xcconfig"; path = "Target Support Files/Pods-Bremer-BremerUITests/Pods-Bremer-BremerUITests.release.xcconfig"; sourceTree = ""; }; + FC8C292B22132B93E2D33CE9 /* Pods-Bremer.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Bremer.release.xcconfig"; path = "Target Support Files/Pods-Bremer/Pods-Bremer.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 383999A62A065DD3005DAB56 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5DA23E753A5913DC36665E82 /* Pods_Bremer.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 38006C462A81F2920027A05C /* Model */ = { + isa = PBXGroup; + children = ( + 38006C402A7E3FCC0027A05C /* ApiModel.swift */, + 38317EDE2AAC6D55003193B7 /* Error.swift */, + ); + path = Model; + sourceTree = ""; + }; + 38006C472A81F2990027A05C /* ViewModel */ = { + isa = PBXGroup; + children = ( + 3847F0242A6501FC00DDB350 /* BremerApi.swift */, + 3847F01C2A64117900DDB350 /* AudioPlayerViewModel.swift */, + 38006C492A81F5770027A05C /* AllPlaylistViewModel.swift */, + 382AB9652A93B88800928393 /* PlaylistAudioViewModel.swift */, + 382AB9672A93B8F300928393 /* TagAudioViewModel.swift */, + 382AB9692A93B93F00928393 /* SearchAudioViewModel.swift */, + 382AB96B2A93B95900928393 /* LatestRecentlyPlayedAudioViewModel.swift */, + 382AB9732A964D5A00928393 /* AllTagsViewModel.swift */, + 38FB93602A9A16FA00967B01 /* SettingViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + 38006C482A81F2A40027A05C /* View */ = { + isa = PBXGroup; + children = ( + 383999AE2A065DD3005DAB56 /* ContentView.swift */, + 38ECE1D02A4B31110044E913 /* LoginWebView.swift */, + 3847F0202A6447C700DDB350 /* PlaylistView.swift */, + 3847F0222A64FAA900DDB350 /* SearchView.swift */, + 38006C442A7FEE640027A05C /* TagView.swift */, + 38006C422A7E42240027A05C /* AudioPlayerView.swift */, + 382AB95F2A8BBC5A00928393 /* ToastView.swift */, + 382AB9612A90DC4300928393 /* LatestRecentlyPlayedView.swift */, + 382AB96F2A93B9D900928393 /* LocalView.swift */, + 38FB93622A9A257C00967B01 /* SettingView.swift */, + 38317EDB2AABF9AA003193B7 /* Component */, + 38FB93702AA2DE7500967B01 /* Alert */, + 38317EDC2AAC12C0003193B7 /* RenameAudioView.swift */, + ); + path = View; + sourceTree = ""; + }; + 382AB9752A99FD8D00928393 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 382AB9782A9A00E800928393 /* Realm */, + 382AB9772A9A00E800928393 /* RealmSwift */, + 382AB9762A99FD8D00928393 /* Cartfile */, + 9ABE7FFD426EF8354B37CD27 /* Pods_Bremer.framework */, + 74CD6B89272147713072414F /* Pods_Bremer_BremerUITests.framework */, + 70A47812EFF9D6BB89E5CF8A /* Pods_BremerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 38317EDB2AABF9AA003193B7 /* Component */ = { + isa = PBXGroup; + children = ( + 38317ED92AA8BA15003193B7 /* NameAlertView.swift */, + 3847F0282A6C121100DDB350 /* LoginButton.swift */, + ); + path = Component; + sourceTree = ""; + }; + 383999A02A065DD3005DAB56 = { + isa = PBXGroup; + children = ( + 383999AB2A065DD3005DAB56 /* BremerApp */, + 383999AA2A065DD3005DAB56 /* Products */, + 382AB9752A99FD8D00928393 /* Frameworks */, + 9240BFFC3ACAA5636920E5CA /* Pods */, + ); + sourceTree = ""; + }; + 383999AA2A065DD3005DAB56 /* Products */ = { + isa = PBXGroup; + children = ( + 383999A92A065DD3005DAB56 /* Bremer.app */, + ); + name = Products; + sourceTree = ""; + }; + 383999AB2A065DD3005DAB56 /* BremerApp */ = { + isa = PBXGroup; + children = ( + 38006C482A81F2A40027A05C /* View */, + 38006C472A81F2990027A05C /* ViewModel */, + 38006C462A81F2920027A05C /* Model */, + 3883C6EC2A0A88280059FE42 /* Info.plist */, + 383999AC2A065DD3005DAB56 /* BremerApp.swift */, + 383999B02A065DD4005DAB56 /* Assets.xcassets */, + 383999B22A065DD4005DAB56 /* Preview Content */, + ); + path = BremerApp; + sourceTree = ""; + }; + 383999B22A065DD4005DAB56 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 383999B32A065DD4005DAB56 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + 38FB93702AA2DE7500967B01 /* Alert */ = { + isa = PBXGroup; + children = ( + 38FB93662AA2DCA400967B01 /* SearchDetailAlertView.swift */, + 38FB936E2AA2DE5D00967B01 /* RenameAudioAlertView.swift */, + ); + path = Alert; + sourceTree = ""; + }; + 9240BFFC3ACAA5636920E5CA /* Pods */ = { + isa = PBXGroup; + children = ( + F0DD7A4E777DA2CCA7D3A5FF /* Pods-Bremer.debug.xcconfig */, + FC8C292B22132B93E2D33CE9 /* Pods-Bremer.release.xcconfig */, + BB5810515AC8560C0B62517E /* Pods-Bremer-BremerUITests.debug.xcconfig */, + F38464A7DA34FCACEC507C2B /* Pods-Bremer-BremerUITests.release.xcconfig */, + 9EFB19BFE75A26E2FB4FFDF4 /* Pods-BremerTests.debug.xcconfig */, + 176731527F753820AF2F9A4D /* Pods-BremerTests.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 383999A82A065DD3005DAB56 /* Bremer */ = { + isa = PBXNativeTarget; + buildConfigurationList = 383999CD2A065DD5005DAB56 /* Build configuration list for PBXNativeTarget "Bremer" */; + buildPhases = ( + FA7D0BBF382AB2636133B42E /* [CP] Check Pods Manifest.lock */, + 383999A52A065DD3005DAB56 /* Sources */, + 383999A62A065DD3005DAB56 /* Frameworks */, + 383999A72A065DD3005DAB56 /* Resources */, + 8F7E7F03FC2F761553B82717 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Bremer; + productName = SampleApp2; + productReference = 383999A92A065DD3005DAB56 /* Bremer.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 383999A12A065DD3005DAB56 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1420; + LastUpgradeCheck = 1420; + TargetAttributes = { + 383999A82A065DD3005DAB56 = { + CreatedOnToolsVersion = 14.2; + }; + }; + }; + buildConfigurationList = 383999A42A065DD3005DAB56 /* Build configuration list for PBXProject "Bremer" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 383999A02A065DD3005DAB56; + productRefGroup = 383999AA2A065DD3005DAB56 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 383999A82A065DD3005DAB56 /* Bremer */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 383999A72A065DD3005DAB56 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 383999B42A065DD4005DAB56 /* Preview Assets.xcassets in Resources */, + 383999B12A065DD4005DAB56 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 8F7E7F03FC2F761553B82717 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Bremer/Pods-Bremer-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Bremer/Pods-Bremer-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Bremer/Pods-Bremer-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + FA7D0BBF382AB2636133B42E /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Bremer-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 383999A52A065DD3005DAB56 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 382AB96A2A93B93F00928393 /* SearchAudioViewModel.swift in Sources */, + 3847F0212A6447C700DDB350 /* PlaylistView.swift in Sources */, + 38ECE1D12A4B31110044E913 /* LoginWebView.swift in Sources */, + 38006C452A7FEE640027A05C /* TagView.swift in Sources */, + 38FB93632A9A257C00967B01 /* SettingView.swift in Sources */, + 3847F0252A6501FC00DDB350 /* BremerApi.swift in Sources */, + 3847F01D2A64117900DDB350 /* AudioPlayerViewModel.swift in Sources */, + 38317EDF2AAC6D55003193B7 /* Error.swift in Sources */, + 38FB93612A9A16FA00967B01 /* SettingViewModel.swift in Sources */, + 382AB9682A93B8F300928393 /* TagAudioViewModel.swift in Sources */, + 38006C432A7E42240027A05C /* AudioPlayerView.swift in Sources */, + 3847F0232A64FAA900DDB350 /* SearchView.swift in Sources */, + 382AB9602A8BBC5A00928393 /* ToastView.swift in Sources */, + 38FB93672AA2DCA400967B01 /* SearchDetailAlertView.swift in Sources */, + 38317EDD2AAC12C0003193B7 /* RenameAudioView.swift in Sources */, + 383999AF2A065DD3005DAB56 /* ContentView.swift in Sources */, + 38006C4A2A81F5770027A05C /* AllPlaylistViewModel.swift in Sources */, + 383999AD2A065DD3005DAB56 /* BremerApp.swift in Sources */, + 382AB9742A964D5A00928393 /* AllTagsViewModel.swift in Sources */, + 382AB96C2A93B95900928393 /* LatestRecentlyPlayedAudioViewModel.swift in Sources */, + 382AB9702A93B9D900928393 /* LocalView.swift in Sources */, + 38317EDA2AA8BA15003193B7 /* NameAlertView.swift in Sources */, + 38006C412A7E3FCC0027A05C /* ApiModel.swift in Sources */, + 382AB9662A93B88800928393 /* PlaylistAudioViewModel.swift in Sources */, + 382AB9622A90DC4300928393 /* LatestRecentlyPlayedView.swift in Sources */, + 38FB936F2AA2DE5D00967B01 /* RenameAudioAlertView.swift in Sources */, + 3847F0292A6C121100DDB350 /* LoginButton.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 383999CB2A065DD5005DAB56 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 383999CC2A065DD5005DAB56 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 383999CE2A065DD5005DAB56 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F0DD7A4E777DA2CCA7D3A5FF /* Pods-Bremer.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"BremerApp/Preview Content\""; + DEVELOPMENT_TEAM = 3LHSST2GWN; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = BremerApp/Info.plist; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = jp.alicja.SampleApp2; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 383999CF2A065DD5005DAB56 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FC8C292B22132B93E2D33CE9 /* Pods-Bremer.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"BremerApp/Preview Content\""; + DEVELOPMENT_TEAM = 3LHSST2GWN; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = BremerApp/Info.plist; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = jp.alicja.SampleApp2; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 383999A42A065DD3005DAB56 /* Build configuration list for PBXProject "Bremer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 383999CB2A065DD5005DAB56 /* Debug */, + 383999CC2A065DD5005DAB56 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 383999CD2A065DD5005DAB56 /* Build configuration list for PBXNativeTarget "Bremer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 383999CE2A065DD5005DAB56 /* Debug */, + 383999CF2A065DD5005DAB56 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 383999A12A065DD3005DAB56 /* Project object */; +} diff --git a/Bremer.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Bremer.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..9b7f874 --- /dev/null +++ b/Bremer.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Bremer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bremer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Bremer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bremer.xcodeproj/project.xcworkspace/xcuserdata/alisha.xcuserdatad/IDEFindNavigatorScopes.plist b/Bremer.xcodeproj/project.xcworkspace/xcuserdata/alisha.xcuserdatad/IDEFindNavigatorScopes.plist new file mode 100644 index 0000000..5dd5da8 --- /dev/null +++ b/Bremer.xcodeproj/project.xcworkspace/xcuserdata/alisha.xcuserdatad/IDEFindNavigatorScopes.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/Bremer.xcodeproj/project.xcworkspace/xcuserdata/alisha.xcuserdatad/xcdebugger/Expressions.xcexplist b/Bremer.xcodeproj/project.xcworkspace/xcuserdata/alisha.xcuserdatad/xcdebugger/Expressions.xcexplist new file mode 100644 index 0000000..f6f67d9 --- /dev/null +++ b/Bremer.xcodeproj/project.xcworkspace/xcuserdata/alisha.xcuserdatad/xcdebugger/Expressions.xcexplist @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Bremer.xcodeproj/xcuserdata/alisha.xcuserdatad/IDETemplateMacros.plist b/Bremer.xcodeproj/xcuserdata/alisha.xcuserdatad/IDETemplateMacros.plist new file mode 100644 index 0000000..d2996ad --- /dev/null +++ b/Bremer.xcodeproj/xcuserdata/alisha.xcuserdatad/IDETemplateMacros.plist @@ -0,0 +1,14 @@ + + + + + FILEHEADER + +// ___FILENAME___ +// ___TARGETNAME___ +// +// Created by yhornisse on ___DATE___. +// ___COPYRIGHT___ + + + diff --git a/Bremer.xcodeproj/xcuserdata/alisha.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Bremer.xcodeproj/xcuserdata/alisha.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..e8e782d --- /dev/null +++ b/Bremer.xcodeproj/xcuserdata/alisha.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/Bremer.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/xcschememanagement.plist b/Bremer.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..09fe2d8 --- /dev/null +++ b/Bremer.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,40 @@ + + + + + SchemeUserState + + Bremer.xcscheme_^#shared#^_ + + orderHint + 5 + + MyPlayground (Playground) 1.xcscheme + + isShown + + orderHint + 2 + + MyPlayground (Playground) 2.xcscheme + + isShown + + orderHint + 3 + + MyPlayground (Playground).xcscheme + + isShown + + orderHint + 0 + + SampleApp2.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/Bremer.xcworkspace/contents.xcworkspacedata b/Bremer.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..0650f5e --- /dev/null +++ b/Bremer.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Bremer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bremer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Bremer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bremer.xcworkspace/xcuserdata/alisha.xcuserdatad/IDEFindNavigatorScopes.plist b/Bremer.xcworkspace/xcuserdata/alisha.xcuserdatad/IDEFindNavigatorScopes.plist new file mode 100644 index 0000000..5dd5da8 --- /dev/null +++ b/Bremer.xcworkspace/xcuserdata/alisha.xcuserdatad/IDEFindNavigatorScopes.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/Bremer.xcworkspace/xcuserdata/alisha.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Bremer.xcworkspace/xcuserdata/alisha.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..1f3b88c --- /dev/null +++ b/Bremer.xcworkspace/xcuserdata/alisha.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/BremerApp/Assets.xcassets/AccentColor.colorset/Contents.json b/BremerApp/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/BremerApp/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BremerApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/BremerApp/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..f497781 --- /dev/null +++ b/BremerApp/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "bremer.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BremerApp/Assets.xcassets/AppIcon.appiconset/bremer.png b/BremerApp/Assets.xcassets/AppIcon.appiconset/bremer.png new file mode 100644 index 0000000..62afd4a --- /dev/null +++ b/BremerApp/Assets.xcassets/AppIcon.appiconset/bremer.png Binary files differ diff --git a/BremerApp/Assets.xcassets/Contents.json b/BremerApp/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/BremerApp/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BremerApp/BremerApp.swift b/BremerApp/BremerApp.swift new file mode 100644 index 0000000..9dbc1f0 --- /dev/null +++ b/BremerApp/BremerApp.swift @@ -0,0 +1,22 @@ +// +// BremerApp.swift +// Bremer +// +// Created by yhornisse on 2023/05/06. +// + +import SwiftUI + +@main +struct BremerApp: App { + var body: some Scene { + WindowGroup { + ContentView() + .environmentObject(AudioPlayerViewModel()) + .environmentObject(PlaylistAudioViewModel()) + .environmentObject(TagAudioViewModel()) + .environmentObject(SearchAudioViewModel()) + .environmentObject(SettingViewModel()) + } + } +} diff --git a/BremerApp/Info.plist b/BremerApp/Info.plist new file mode 100644 index 0000000..fa93336 --- /dev/null +++ b/BremerApp/Info.plist @@ -0,0 +1,24 @@ + + + + + NSAppTransportSecurity + + NSExceptionDomains + + pied-piper.net + + NSTemporaryExceptionAllowsInsecureHTTPLoads + + + + + UIBackgroundModes + + audio + fetch + processing + remote-notification + + + diff --git a/BremerApp/Model/ApiModel.swift b/BremerApp/Model/ApiModel.swift new file mode 100644 index 0000000..6aaf892 --- /dev/null +++ b/BremerApp/Model/ApiModel.swift @@ -0,0 +1,72 @@ +// +// ApiModel.swift +// Bremer +// +// Created by yhornisse on 2023/08/05. +// + +struct AudioApiResponse: Codable { + var audioList: [Audio] +} + +struct Audio: Codable { + var name: String + var slug: String + var artist: String? + var album: String? + var sequence: Int? + var aliasNames: [String]? + var localPath: String +} + +struct AllPlaylistApiResponse: Codable { + var playlist: [Playlist] +} + +struct Playlist: Codable { + var name: String + var slug: String +} + +struct PlaylistApiResponse: Codable { + var name: String + var slug: String + var audioList: [Audio] +} + +struct TagRequest: Codable { + var name: String +} + +struct TagAudioRequest: Codable { + var audioSlugs: [String] +} + +struct Tag: Codable { + var name: String + var slug: String +} + +struct AllTagsApiResponse: Codable { + var tags: [Tag] +} + +struct TagApiResponse: Codable { + var name: String + var slug: String + var audioList: [Audio] +} + +struct PlaylistRequest: Codable { + var name: String +} + +struct PlaylistAudioRequest: Codable { + var audioSlugs: [String] +} + +struct AudioRequest : Codable { + var name: String + var artist: String + var album: String +} diff --git a/BremerApp/Model/Error.swift b/BremerApp/Model/Error.swift new file mode 100644 index 0000000..79ad399 --- /dev/null +++ b/BremerApp/Model/Error.swift @@ -0,0 +1,16 @@ +// +// Error.swift +// Bremer +// +// Created by yhornisse on 2023/09/09. +// + + +import Foundation + +class BremerConnectionError : Error { +} + +class BremerLoginError : Error { + +} diff --git a/BremerApp/Preview Content/Preview Assets.xcassets/Contents.json b/BremerApp/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/BremerApp/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BremerApp/View/Alert/RenameAudioAlertView.swift b/BremerApp/View/Alert/RenameAudioAlertView.swift new file mode 100644 index 0000000..8108c8f --- /dev/null +++ b/BremerApp/View/Alert/RenameAudioAlertView.swift @@ -0,0 +1,46 @@ +// +// RenameAudioAlertView.swift +// Bremer +// +// Created by yhornisse on 2023/09/02. +// + + +import SwiftUI + +struct RenameAudioAlertView : View { + @State + var audioInfo : AudioInfo + var onOk: (_ audioInfo: AudioInfo) -> Void + var onError: (_ message: String) -> Void + + var body : some View { + TextField("曲名", text: $audioInfo.audioName) + TextField("歌手名", text: $audioInfo.artistName) + TextField("アルバム名", text: $audioInfo.albumName) + TextField("ローカルパス(変更不可)", text: $audioInfo.localPath) + .disabled(true) // TODO 効かないがいずれ治す + Button("OK", role: .cancel){ + if audioInfo.audioName.isEmpty { + self.onError("名前の変更に失敗しました") + return + } + if audioInfo.albumName.isEmpty { + self.onError("名前の変更に失敗しました") + return + } + self.onOk(audioInfo) + clear() + } + Button("キャンセル", role: .destructive){ + clear() + } + } + + func clear() { + self.audioInfo.audioName = "" + self.audioInfo.artistName = "" + self.audioInfo.albumName = "" + } +} + diff --git a/BremerApp/View/Alert/SearchDetailAlertView.swift b/BremerApp/View/Alert/SearchDetailAlertView.swift new file mode 100644 index 0000000..00eb511 --- /dev/null +++ b/BremerApp/View/Alert/SearchDetailAlertView.swift @@ -0,0 +1,36 @@ +// +// SearchDetailAlertView.swift +// Bremer +// +// Created by yhornisse on 2023/09/02. +// + +import SwiftUI + +struct SearchDetailAlertView : View { + var searchAction: (_ audio: String, _ artist: String, _ album: String, _ tag: String) -> Void + @State + private var audioName = "" + @State + private var artistName = "" + @State + private var albumName = "" + @State + private var tagName = "" + + var body : some View { + TextField("曲名", text: $audioName) + TextField("歌手名", text: $artistName) + TextField("アルバム名", text: $albumName) + TextField("タグ名", text: $tagName) + Button("検索", role: .cancel){ + searchAction(audioName, artistName, albumName, tagName) + } + Button("キャンセル", role: .destructive){ + self.audioName = "" + self.artistName = "" + self.albumName = "" + self.tagName = "" + } + } +} diff --git a/BremerApp/View/AudioPlayerView.swift b/BremerApp/View/AudioPlayerView.swift new file mode 100644 index 0000000..ffcd0d4 --- /dev/null +++ b/BremerApp/View/AudioPlayerView.swift @@ -0,0 +1,65 @@ +// +// AudioPlayerView.swift +// Bremer +// +// Created by yhornisse on 2023/08/05. +// + +import SwiftUI + +struct AudioPlayerView : View { + @ObservedObject + var audioPlayerViewModel : AudioPlayerViewModel + @State + var playingTime = "00:00 / 00:00" + @State + var playingTimeRate : Double = 0.0 + + var body : some View { + let timer = Timer.publish(every: 0.3, on: .main, in: .common).autoconnect() + VStack { + Text("\(audioPlayerViewModel.playingMusic?.name ?? "") - \(audioPlayerViewModel.playingMusic?.album ?? "")") + .font(.system(size: 14)) + .frame(height: 35, alignment: .center) + .aspectRatio(contentMode: .fit) + Slider(value: $playingTimeRate, + onEditingChanged: { editing in + audioPlayerViewModel.setAudioSeq(seq: playingTimeRate * (audioPlayerViewModel.musicPlayer?.duration ?? 0.0)) + }) + .onReceive(timer, perform: {time in + playingTimeRate = audioPlayerViewModel.musicTimeRate() + }) + if audioPlayerViewModel.musicPlayer != nil { + if audioPlayerViewModel.isPlaying == true { + Button(action: { + audioPlayerViewModel.pauseAudio() + }) { + Image(systemName: "pause.fill") + .resizable() + .scaledToFill() + .frame(width: 20, height: 20) + } + } else { + Button(action: { + audioPlayerViewModel.playAudio() + }) { + Image(systemName: "play.fill") + .resizable() + .scaledToFill() + .frame(width: 20, height: 20) + } + } + } else { + Image(systemName: "play.slash") + .resizable() + .scaledToFill() + .frame(width: 20, height: 20) + } + Text(playingTime) + .font(Font(UIFont.monospacedSystemFont(ofSize: 18.0, weight: .regular))) + .onReceive(timer, perform: {time in + playingTime = audioPlayerViewModel.musicTime() + }) + } + } +} diff --git a/BremerApp/View/Component/LoginButton.swift b/BremerApp/View/Component/LoginButton.swift new file mode 100644 index 0000000..c82ebca --- /dev/null +++ b/BremerApp/View/Component/LoginButton.swift @@ -0,0 +1,24 @@ +// +// CommonView.swift +// Bremer +// +// Created by yhornisse on 2023/07/22. +// + +import SwiftUI + +struct LoginButton : View { + var action : () -> Void + var body : some View { + VStack { + Button(action: action) { + HStack { + Text("Login Now") + Image(systemName: "door.left.hand.open") + } + } + .buttonStyle(.bordered) + } + } +} + diff --git a/BremerApp/View/Component/NameAlertView.swift b/BremerApp/View/Component/NameAlertView.swift new file mode 100644 index 0000000..caa69b6 --- /dev/null +++ b/BremerApp/View/Component/NameAlertView.swift @@ -0,0 +1,35 @@ +// +// NameAlertView.swift +// Bremer +// +// Created by yhornisse on 2023/09/06. +// + + +import SwiftUI + +struct NameAlertView : View { + var label : String + var act : String + @State + var input : String = "" + var onOk: (_ input: String) -> Void + var onError: (_ message: String) -> Void + @State + var errorAlertTitle = "" + + var body : some View { + TextField("\(label)名", text: $input) + Button("OK", role: .cancel){ + if input.isEmpty { + self.onError("\(label)の\(act)に失敗しました") + return + } + self.onOk(input) + self.input = "" + } + Button("キャンセル", role: .destructive){ + self.input = "" + } + } +} diff --git a/BremerApp/View/Component/ToastView.swift b/BremerApp/View/Component/ToastView.swift new file mode 100644 index 0000000..d778c31 --- /dev/null +++ b/BremerApp/View/Component/ToastView.swift @@ -0,0 +1,32 @@ +// +// ToastView.swift +// Bremer +// +// Created by yhornisse on 2023/08/15. +// + +import SwiftUI + +struct ToastView: View { + var message: String + var body: some View { + VStack(alignment: .leading) { + HStack(alignment: .top) { + VStack(alignment: .leading) { + Text(message) + .font(.system(size: 14)) + .frame(height: 35, alignment: .center) + .aspectRatio(contentMode: .fit) + } + + Spacer(minLength: 10) + } + .padding() + } + .background(Color.gray) + .frame(minWidth: 0, maxWidth: .infinity) + .cornerRadius(8) + .padding(.horizontal, 16) + } +} + diff --git a/BremerApp/View/ContentView.swift b/BremerApp/View/ContentView.swift new file mode 100644 index 0000000..c4d98ae --- /dev/null +++ b/BremerApp/View/ContentView.swift @@ -0,0 +1,65 @@ +// +// ContentView.swift +// Bremer +// +// Created by yhornisse on 2023/05/06. +// + +import SwiftUI + +struct ContentView: View { + + var body: some View { + VStack { + TabView { + PlaylistTopView() + .tabItem { + VStack { + Image(systemName: "music.note.list") + Text("Playlist") + } + } + TagTopView() + .tabItem { + VStack { + Image(systemName: "tag") + Text("Tag") + } + } + SearchView() + .tabItem { + VStack { + Image(systemName: "magnifyingglass") + Text("Search") + } + } + LatestRecentlyPlayedView() + .tabItem { + VStack { + Image(systemName: "list.triangle") + Text("Recent") + } + } + LocalView() + .tabItem { + VStack { + Image(systemName: "wifi.exclamationmark") + Text("Offline") + } + } + SettingView() + .tabItem { + Image(systemName: "gearshape") + Text("Configuration") + } + } + .scrollDismissesKeyboard(.immediately) + } + } +} + +struct ContentView_Preview: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/BremerApp/View/LatestRecentlyPlayedView.swift b/BremerApp/View/LatestRecentlyPlayedView.swift new file mode 100644 index 0000000..d8eca1a --- /dev/null +++ b/BremerApp/View/LatestRecentlyPlayedView.swift @@ -0,0 +1,119 @@ +// +// LatestRecentlyPlayedView.swift +// Bremer +// +// Created by yhornisse on 2023/08/19. +// + +import SwiftUI +import AVFoundation + +struct LatestRecentlyPlayedView : View { + + @State + private var showedLoginView = false + @State + private var showedUpdateAudioDialog = false + @State + private var audioTargetSlug = "" + @State + private var audioInfo = AudioInfo() + @State + private var errorAlertTitle = "" + @State + private var showedErrorAlert = false + @EnvironmentObject + private var audioPlayerViewModel : AudioPlayerViewModel + @EnvironmentObject + private var settingViewModel : SettingViewModel + @ObservedObject + private var latestRecentlyPlayedAudioViewModel = LatestRecentlyPlayedAudioViewModel() + + var body : some View { + VStack { + Text("再生履歴") + if settingViewModel.getSetting().baseUrl == "" { + Text("Base URLを設定してください") + } else if !latestRecentlyPlayedAudioViewModel.messageText.isEmpty { + if (latestRecentlyPlayedAudioViewModel.hasError) { + VStack { + Text(latestRecentlyPlayedAudioViewModel.messageText) + .foregroundColor(.red) + if latestRecentlyPlayedAudioViewModel.messageText == "ログインしてください" { + LoginButton(action: { + self.showedLoginView = true + }) + } + } + } else { + Text(latestRecentlyPlayedAudioViewModel.messageText) + } + } + List { + ForEach(latestRecentlyPlayedAudioViewModel.result, id:\.slug) { audio in + Button(action: { + audioPlayerViewModel.playAudioList( + audioList: latestRecentlyPlayedAudioViewModel.result, audio: audio, usedBy: "recent") + }) { + Text("\(audio.name) - \(audio.album ?? "")") + .font(.system(size: 14)) + .frame(height: 35, alignment: .center) + .aspectRatio(contentMode: .fit) + } + .swipeActions(edge: .trailing) { + Button { + self.audioTargetSlug = audio.slug + self.audioInfo.audioName = audio.name + self.audioInfo.artistName = audio.artist ?? "" + self.audioInfo.albumName = audio.album ?? "" + self.audioInfo.localPath = audio.localPath + self.showedUpdateAudioDialog = true + } label: { + Text("変更") + } + .tint(.green) + } + } + } + .listStyle(.plain) + Spacer() + Divider() + AudioPlayerView(audioPlayerViewModel: audioPlayerViewModel) + } + .sheet(isPresented: $showedLoginView) { + LoginWebView() + } + .alert("更新", isPresented: $showedUpdateAudioDialog) { + RenameAudioAlertView(audioInfo: self.audioInfo) {(audioInfo: AudioInfo) in + latestRecentlyPlayedAudioViewModel.updateAudio( + slug: audioTargetSlug, + audioName: audioInfo.audioName, + artistName: audioInfo.artistName, + albumName: audioInfo.albumName) + } onError: {(message: String) in + self.errorAlertTitle = message + self.showedErrorAlert = true + } + } message: { + Text("新しい名前を入力してください") + } + .alert(errorAlertTitle, isPresented: $showedErrorAlert, actions: { + Button(action: { + // nop + }, label: { + Text("確認") + }) + }) + .onAppear { + latestRecentlyPlayedAudioViewModel.bremerApiBaseUrl = settingViewModel.getSetting().baseApiUrl() + latestRecentlyPlayedAudioViewModel.getAllAudio() + } + .onReceive(NotificationCenter.default.publisher(for: AVAudioSession.routeChangeNotification), perform: { param in + audioPlayerViewModel.onChangeAudioSessionRoute(param) + }) + .onReceive(NotificationCenter.default.publisher(for: AVAudioSession.interruptionNotification), perform: { param in + audioPlayerViewModel.onInterrupted(param) + }) + } +} + diff --git a/BremerApp/View/LocalView.swift b/BremerApp/View/LocalView.swift new file mode 100644 index 0000000..780d65c --- /dev/null +++ b/BremerApp/View/LocalView.swift @@ -0,0 +1,50 @@ +// +// LocalView.swift +// Bremer +// +// Created by yhornisse on 2023/08/22. +// + +import SwiftUI +import AVFoundation + +struct LocalView : View { + + @EnvironmentObject + private var audioPlayerViewModel : AudioPlayerViewModel + + var body : some View { + VStack { + Text("ダウンロード済") + List { + ForEach(audioPlayerViewModel.audioQueue, id:\.slug) {audio in + Button(action: { + if audioPlayerViewModel.exists(audio.slug) { + audioPlayerViewModel.playAudioList(audioList: audioPlayerViewModel.audioQueue, + audio: audio, + usedBy: "local") + } else { + // TODO 削除して詰める +// localAudioPlayerViewModel.remove + } + }) { + Text("\(audio.name) - \(audio.album ?? "")") + .font(.system(size: 14)) + .frame(height: 35, alignment: .center) + .aspectRatio(contentMode: .fit) + } + } + } + .listStyle(.plain) + Spacer() + Divider() + AudioPlayerView(audioPlayerViewModel: audioPlayerViewModel) + } + .onReceive(NotificationCenter.default.publisher(for: AVAudioSession.routeChangeNotification), perform: { param in + audioPlayerViewModel.onChangeAudioSessionRoute(param) + }) + .onReceive(NotificationCenter.default.publisher(for: AVAudioSession.interruptionNotification), perform: { param in + audioPlayerViewModel.onInterrupted(param) + }) + } +} diff --git a/BremerApp/View/LoginWebView.swift b/BremerApp/View/LoginWebView.swift new file mode 100644 index 0000000..8bf71ce --- /dev/null +++ b/BremerApp/View/LoginWebView.swift @@ -0,0 +1,51 @@ +// +// LoginWebView.swift +// Bremer +// +// Created by yhornisse on 2023/07/17. +// + +import SwiftUI +import WebKit + +struct LoginWebView: UIViewRepresentable { + private let webView = WKWebView() + @EnvironmentObject + private var settingViewModel : SettingViewModel + + func makeUIView(context: Context) -> WKWebView { + webView.navigationDelegate = context.coordinator + webView.load(URLRequest(url: URL(string:"\(settingViewModel.getSetting().baseUrl)/login.html")!)) + return webView + } + + func updateUIView(_ uiView: WKWebView, context: Context) { + } + + func makeCoordinator() -> Coordinator { + return Coordinator(self) + } +} + +extension LoginWebView { + class Coordinator: NSObject, WKNavigationDelegate { + private var parent: LoginWebView + private let cookieName = "JSESSIONID" + + init(_ parent: LoginWebView) { + self.parent = parent + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in + for cookie in cookies { + if cookie.name == self.cookieName { + UserDefaults.standard.set(cookie.value, forKey: self.cookieName) + webView.configuration.websiteDataStore.httpCookieStore.delete(cookie) + return + } + } + } + } + } +} diff --git a/BremerApp/View/PlaylistView.swift b/BremerApp/View/PlaylistView.swift new file mode 100644 index 0000000..e0810c6 --- /dev/null +++ b/BremerApp/View/PlaylistView.swift @@ -0,0 +1,359 @@ +// +// PlaylistView.swift +// Bremer +// +// Created by yhornisse on 2023/07/17. +// + +import SwiftUI + +struct PlaylistTopView : View { + + @State var filterText = "" + @State var showedLoginView = false + @State var playlistNewName = "" + @State var playlistTargetSlug = "" + @State var showedNewPlaylistDialog = false + @State var showedUpdatePlaylistDialog = false + @State var showedErrorAlert = false + @State var showedDeletePlaylistDialog = false + @State private var errorAlertTitle = "" + @EnvironmentObject private var settingViewModel : SettingViewModel + @ObservedObject var allPlaylistViewModel = AllPlaylistViewModel() + + var filterResults: [Playlist] { + if filterText.isEmpty { + return allPlaylistViewModel.playlists + } else { + return allPlaylistViewModel.playlists.filter { $0.name.contains(filterText) } + } + } + + var body : some View { + NavigationView { + VStack { + if settingViewModel.getSetting().baseUrl == "" { + Text("Base URLを設定してください") + } else if !allPlaylistViewModel.messageText.isEmpty { + if allPlaylistViewModel.hasError { + Text(allPlaylistViewModel.messageText) + .foregroundColor(.red) + if allPlaylistViewModel.messageText == "ログインしてください" { + LoginButton(action: { + self.showedLoginView = true + }) + } + } else { + Text(allPlaylistViewModel.messageText) + } + } + List { + ForEach(filterResults, id:\.slug) { playlist in + NavigationLink(destination: PlaylistDescView(slug: playlist.slug)) { + Text(playlist.name) + .buttonStyle(.bordered) + .font(.system(size: 16)) + .aspectRatio(contentMode: .fit) + } + .swipeActions(edge: .trailing) { + Button { + self.playlistTargetSlug = playlist.slug + self.showedDeletePlaylistDialog = true + } label: { + Text("削除") + } + .tint(.red) + Button { + self.playlistTargetSlug = playlist.slug + self.playlistNewName = playlist.name + self.showedUpdatePlaylistDialog = true + } label: { + Text("変更") + } + .tint(.green) + } + } + } + .listStyle(.plain) + .searchable(text: $filterText, prompt: "検索キーワード") + .keyboardType(.default) + } + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button(action: { + self.playlistNewName = "" + self.showedNewPlaylistDialog = true + }) { + Image(systemName: "plus.app") + } + } + } + .alert("新規登録", isPresented: $showedNewPlaylistDialog) { + NameAlertView(label: "プレイリスト", act: "追加", onOk: allPlaylistViewModel.createPlaylist) {(message: String) in + self.showedErrorAlert = true + self.errorAlertTitle = message + } + } message: { + Text("プレイリスト名を入力してください") + } + .alert("更新", isPresented: $showedUpdatePlaylistDialog) { + NameAlertView(label: "プレイリスト", act: "変更", input: playlistNewName) {(name: String) in allPlaylistViewModel.updatePlaylist(playlistTargetSlug, name) + } onError : {(message: String) in + self.showedErrorAlert = true + self.errorAlertTitle = message + } + } message: { + Text("プレイリスト名を入力してください") + } + .confirmationDialog( + "プレイリスト削除", + isPresented: $showedDeletePlaylistDialog, + actions: { + Button("OK", role: .destructive){ + allPlaylistViewModel.deletePlaylist(playlistTargetSlug) + } + Button("キャンセル", role: .cancel){ + self.playlistNewName = "" + } + }, message: { + Text( "本当にプレイリストを削除しますか?") + }) + .alert(errorAlertTitle, isPresented: $showedErrorAlert, actions: { + Button(action: { + // nop + }, label: { + Text("確認") + }) + }) + } + .sheet(isPresented: $showedLoginView) { + LoginWebView() + .onDisappear { + allPlaylistViewModel.getAllPlaylist() + } + } + .scrollDismissesKeyboard(.immediately) + .onAppear { + allPlaylistViewModel.bremerApiBaseUrl = settingViewModel.getSetting().baseApiUrl() + allPlaylistViewModel.getAllPlaylist() + } + } +} + +struct PlaylistDescView : View { + @EnvironmentObject + private var playlistAudioViewModel : PlaylistAudioViewModel + @EnvironmentObject + private var audioPlayerViewModel : AudioPlayerViewModel + @EnvironmentObject + private var configViewModel : SettingViewModel + var slug : String + + var body : some View { + VStack { + if !playlistAudioViewModel.messageText.isEmpty { + if (playlistAudioViewModel.hasError) { + VStack { + Text(playlistAudioViewModel.messageText) + .foregroundColor(.red) + } + } else { + Text(playlistAudioViewModel.messageText) + } + } + List { + ForEach(playlistAudioViewModel.result, id:\.slug) { audio in + Button(action: { + audioPlayerViewModel.playAudioList( + audioList: playlistAudioViewModel.result, audio: audio, usedBy: "playlist") + }) { + Text("\(audio.name) - \(audio.album ?? "")") + .font(.system(size: 14)) + .frame(height: 35, alignment: .center) + .aspectRatio(contentMode: .fit) + } + .swipeActions(edge: .trailing) { + Button { + // TODO 再生中の時は削除する必要ある + self.playlistAudioViewModel.deleteAudioInPlaylist(playlistSlug: slug, audioSlug: audio.slug) + } label: { + Text("削除") + } + .tint(.red) + } + } + .onMove {src, dst in + self.audioPlayerViewModel.reorderAudioList(from: src, to: dst, usedBy: "playlist") + self.playlistAudioViewModel.reorderPlaylist(from: src, to: dst) + self.playlistAudioViewModel.save(slug: slug) + } + } + .listStyle(.plain) + .keyboardType(.default) + Spacer() + Divider() + AudioPlayerView(audioPlayerViewModel: audioPlayerViewModel) + } + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + NavigationLink(destination: PlaylistAddView(slug: slug)){ + Image(systemName: "plus.app") + } + } + } + .onAppear { + self.playlistAudioViewModel.bremerApiBaseUrl = configViewModel.getSetting().baseApiUrl() + self.playlistAudioViewModel.getAllAudio(slug: slug) + } + } +} + +struct PlaylistAddView : View { + @State + var slug : String + @State + private var searchText : String = "" + @State + private var showedLoginView = false + @EnvironmentObject + private var playlistAudioViewModel : PlaylistAudioViewModel + @EnvironmentObject + private var audioPlayerViewModel : AudioPlayerViewModel + @EnvironmentObject + private var searchAudioViewModel : SearchAudioViewModel + @EnvironmentObject + private var configViewModel : SettingViewModel + @State + private var audioTargetSlug = "" + @State + private var showedErrorAlert = false + @State + private var errorAlertTitle = "" + @State + private var audioInfo = AudioInfo() + @State + private var showedToast = false + @State + private var toastMessage = "" + @State + private var showedUpdateAudioDialog = false + @State + var showedSearchAudioDialog = false + @State + var shouldShowSecondView = false + + var body : some View { + NavigationView { + ZStack { + VStack { + if !searchAudioViewModel.messageText.isEmpty { + if (searchAudioViewModel.hasError) { + VStack { + Text(searchAudioViewModel.messageText) + .foregroundColor(.red) + LoginButton(action: { + self.showedLoginView = true + }) + } + } else { + Text(searchAudioViewModel.messageText) + } + } + List { + ForEach(searchAudioViewModel.result, id:\.slug) { audio in + HStack { + Button(action: { + audioPlayerViewModel.playAudioList( + audioList: [audio], audio: audio, usedBy: "playlist-add") + }) { + Text("\(audio.name) - \(audio.album ?? "")") + .font(.system(size: 14)) + .frame(height: 35, alignment: .center) + .aspectRatio(contentMode: .fit) + } + .buttonStyle(PlainButtonStyle()) + Spacer() + Button(action: { + playlistAudioViewModel.addAudio(audio: audio) + audioPlayerViewModel.addAudio(audio: audio, usedBy: "playlist-\(slug)") + playlistAudioViewModel.save(slug: self.slug) + self.toastMessage = "\(audio.name) を追加" + self.showedToast = true + }) { + Image(systemName: "plus.app") + .resizable() + .scaledToFill() + .frame(width: 33, height: 33) + } + .buttonStyle(PlainButtonStyle()) + } + .swipeActions(edge: .trailing) { + Button(action: { + self.audioTargetSlug = audio.slug + self.audioInfo.audioName = audio.name + self.audioInfo.artistName = audio.artist ?? "" + self.audioInfo.albumName = audio.album ?? "" + self.audioInfo.localPath = audio.localPath + // self.showedUpdateAudioDialog = true + self.shouldShowSecondView = true + }) { + Text("変更") + } + .tint(.green) + } + } + } + .listStyle(.plain) + .searchable(text: $searchText, prompt: "検索キーワード") + .onSubmit(of: .search) { + searchAudioViewModel.searchAudio(keyword: searchText) + } + } + if showedToast { + VStack { + Spacer() + ToastView(message: toastMessage) + } + .onAppear(perform: { + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + withAnimation { + self.showedToast = false + } + } + }) + } + } + } + .sheet(isPresented: $showedLoginView) { + LoginWebView() + } + .sheet(isPresented: $shouldShowSecondView) { + RenameAudioView(audioInfo: self.audioInfo){(audioInfo : AudioInfo) in + searchAudioViewModel.updateAudio( + slug: self.audioTargetSlug, + audioName: audioInfo.audioName, + artistName: audioInfo.artistName, + albumName: audioInfo.albumName) + } + } + .scrollDismissesKeyboard(.immediately) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button(action: { + self.showedSearchAudioDialog = true + }) { + Image(systemName: "text.magnifyingglass") + } + } + } + .alert("詳細検索", isPresented: $showedSearchAudioDialog) { + SearchDetailAlertView(searchAction: searchAudioViewModel.searchAudio) + } message: { + Text("新しい名前を入力してください") + } + .onAppear { + searchAudioViewModel.bremerApiBaseUrl = configViewModel.getSetting().baseApiUrl() + searchAudioViewModel.result = [] + } + } +} diff --git a/BremerApp/View/RenameAudioView.swift b/BremerApp/View/RenameAudioView.swift new file mode 100644 index 0000000..07e8a2c --- /dev/null +++ b/BremerApp/View/RenameAudioView.swift @@ -0,0 +1,49 @@ +// +// RenameAudioView.swift +// Bremer +// +// Created by yhornisse on 2023/09/09. +// + + +import SwiftUI + +struct RenameAudioView : View { + @State + var audioInfo : AudioInfo + var onOk: (_ audioInfo: AudioInfo) -> Void + @Environment(\.dismiss) + private var dismiss + + var body : some View { + VStack { + Group { + Text("曲名変更") + Text("曲名:") + .frame(maxWidth: .infinity, alignment: .leading) + TextField("曲名", text: $audioInfo.audioName) + Text("歌手名:") + .frame(maxWidth: .infinity, alignment: .leading) + TextField("歌手名", text: $audioInfo.artistName) + Text("アルバム名:") + .frame(maxWidth: .infinity, alignment: .leading) + TextField("アルバム名", text: $audioInfo.albumName) + Text("ローカルパス:") + .frame(maxWidth: .infinity, alignment: .leading) + Text(audioInfo.localPath) + .textSelection(.enabled) + } + Spacer() + HStack { + Button("保存") { + onOk(audioInfo) + dismiss() + } + Button("キャンセル") { + dismiss() + } + } + } + } +} + diff --git a/BremerApp/View/SearchView.swift b/BremerApp/View/SearchView.swift new file mode 100644 index 0000000..7e94bf1 --- /dev/null +++ b/BremerApp/View/SearchView.swift @@ -0,0 +1,189 @@ +// +// SearchView.swift +// Bremer +// +// Created by yhornisse on 2023/07/17. +// + +import SwiftUI +import AVFoundation + +struct SearchView : View { + + @State + private var searchText : String = "" + @State + private var showedLoginView = false + @State + private var showedUpdateAudioDialog = false + @State + private var showedErrorAlert = false + @State + private var showedSearchAudioDialog = false + @State + private var showedDeleteAudioDialog = false + @State + private var audioTargetSlug = "" + @State + private var audioTargetName = "" + @State + private var audioName = "" + @State + var artistName = "" + @State + private var albumName = "" + @State + private var localPath = "" + @State + private var tagName = "" + @State + private var errorAlertTitle = "" + @EnvironmentObject + private var audioPlayerViewModel : AudioPlayerViewModel + @EnvironmentObject + private var settingViewModel : SettingViewModel + @ObservedObject + private var searchAudioViewModel = SearchAudioViewModel() + + var body : some View { + NavigationView { + VStack { + if settingViewModel.getSetting().baseUrl == "" { + Text("Base URLを設定してください") + } else if !searchAudioViewModel.messageText.isEmpty { + if (searchAudioViewModel.hasError) { + VStack { + Text(searchAudioViewModel.messageText) + .foregroundColor(.red) + if searchAudioViewModel.messageText == "ログインしてください" { + LoginButton(action: { + self.showedLoginView = true + }) + } + } + } else { + Text(searchAudioViewModel.messageText) + } + } + List { + ForEach(searchAudioViewModel.result, id:\.slug) { audio in + Button(action: { + audioPlayerViewModel.playAudioList( + audioList: searchAudioViewModel.result, audio: audio, usedBy: "search") + }) { + Text("\(audio.name) - \(audio.album ?? "")") + .font(.system(size: 14)) + .frame(height: 35, alignment: .center) + .aspectRatio(contentMode: .fit) + } + .swipeActions(edge: .trailing) { + Button { + self.audioTargetSlug = audio.slug + self.audioTargetName = audio.name + self.showedDeleteAudioDialog = true + } label : { + Text("削除") + } + .tint(.red) + Button { + self.audioTargetSlug = audio.slug + self.audioName = audio.name + self.artistName = audio.artist ?? "" + self.albumName = audio.album ?? "" + self.localPath = audio.localPath + self.showedUpdateAudioDialog = true + } label: { + Text("変更") + } + .tint(.green) + } + } + } + .listStyle(.plain) + .searchable(text: $searchText, prompt: "検索キーワード") + .onSubmit(of: .search) { + searchAudioViewModel.searchAudio(keyword: searchText) + } + .alert("更新", isPresented: $showedUpdateAudioDialog) { + TextField("曲名", text: $audioName) + TextField("歌手名", text: $artistName) + TextField("アルバム名", text: $albumName) + TextField("ローカルパス(変更不可)", text: $localPath) + .disabled(true) // TODO 効かないがいずれ治す + Button("OK", role: .cancel){ + if audioName.isEmpty { + self.errorAlertTitle = "名前の変更に失敗しました" + self.showedErrorAlert = true + return + } + if albumName.isEmpty { + self.errorAlertTitle = "名前の変更に失敗しました" + self.showedErrorAlert = true + return + } + searchAudioViewModel.updateAudio( + slug: audioTargetSlug, + audioName: audioName, + artistName: artistName, + albumName: albumName) + } + Button("キャンセル", role: .destructive){ + self.audioName = "" + self.artistName = "" + self.albumName = "" + } + } message: { + Text("新しい名前を入力してください") + } + .confirmationDialog( + "音楽削除", + isPresented: $showedDeleteAudioDialog, + actions: { + Button("OK", role: .destructive){ + searchAudioViewModel.deleteAudio(audioTargetSlug) + } + Button("キャンセル", role: .cancel){ + self.audioTargetSlug = "" + self.audioTargetName = "" + } + }, message: { + Text( "本当に \(audioTargetName) を削除しますか?\n一度消すとアプリからは戻せません!") + }) + Spacer() + Divider() + AudioPlayerView(audioPlayerViewModel: audioPlayerViewModel) + } + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button(action: { + self.showedSearchAudioDialog = true + }) { + Image(systemName: "text.magnifyingglass") + } + } + } + } + .onAppear { + searchAudioViewModel.bremerApiBaseUrl = settingViewModel.getSetting().baseApiUrl() + } + .sheet(isPresented: $showedLoginView) { + LoginWebView() + .onDisappear { + searchAudioViewModel.searchAudio(keyword: searchText) + } + } + .scrollDismissesKeyboard(.immediately) + .onReceive(NotificationCenter.default.publisher(for: AVAudioSession.routeChangeNotification), perform: { param in + audioPlayerViewModel.onChangeAudioSessionRoute(param) + }) + .onReceive(NotificationCenter.default.publisher(for: AVAudioSession.interruptionNotification), perform: { param in + audioPlayerViewModel.onInterrupted(param) + }) + .alert("詳細検索", isPresented: $showedSearchAudioDialog) { + SearchDetailAlertView(searchAction: searchAudioViewModel.searchAudio) + } message: { + Text("新しい名前を入力してください") + } + } +} + diff --git a/BremerApp/View/SettingView.swift b/BremerApp/View/SettingView.swift new file mode 100644 index 0000000..4cffd8b --- /dev/null +++ b/BremerApp/View/SettingView.swift @@ -0,0 +1,33 @@ +// +// SettingView.swift +// Bremer +// +// Created by yhornisse on 2023/08/26. +// + +import SwiftUI + +struct SettingView : View { + + @EnvironmentObject + private var settingViewModel : SettingViewModel + @State + private var baseUrl = "" + + var body : some View { + VStack { + Text("設定") + TextField("Base URL", text: $baseUrl) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .frame(width: 250) + Button(action: { + settingViewModel.updateBaseApiUrl(baseUrl) + }) { + Text("Update") + } + } + .onAppear { + baseUrl = settingViewModel.getSetting().baseUrl + } + } +} diff --git a/BremerApp/View/TagView.swift b/BremerApp/View/TagView.swift new file mode 100644 index 0000000..d734b9f --- /dev/null +++ b/BremerApp/View/TagView.swift @@ -0,0 +1,345 @@ +// +// TagView.swift +// Bremer +// +// Created by yhornisse on 2023/08/07. +// + +import SwiftUI + +struct TagTopView : View { + + @State var filterText = "" + @State var tagNewName = "" + @State var tagTargetSlug = "" + @State var errorAlertTitle = "" + @State var showedLoginView = false + @State var showedNewTagDialog = false + @State var showedUpdateTagDialog = false + @State var showedErrorAlert = false + @EnvironmentObject var settingViewModel : SettingViewModel + @ObservedObject var allTagsViewModel = AllTagsViewModel() + + var filterResults: [Tag] { + if filterText.isEmpty { + return allTagsViewModel.tags + } else { + return allTagsViewModel.tags.filter { $0.name.contains(filterText) } + } + } + + var body : some View { + NavigationView { + VStack { + if settingViewModel.getSetting().baseUrl == "" { + Text("Base URLを設定してください") + } else if !allTagsViewModel.messageText.isEmpty { + if allTagsViewModel.hasError { + Text(allTagsViewModel.messageText) + .foregroundColor(.red) + if allTagsViewModel.messageText == "ログインしてください" { + LoginButton(action: { + self.showedLoginView = true + }) + } + } else { + Text(allTagsViewModel.messageText) + } + } + List { + ForEach(filterResults, id:\.slug) { tag in + NavigationLink(destination: TagDescView(slug: tag.slug)) { + Text(tag.name) + .buttonStyle(.bordered) + .font(.system(size: 16)) + .aspectRatio(contentMode: .fit) + } + .swipeActions(edge: .trailing) { + Button { + allTagsViewModel.deleteTag(tag.slug) + } label: { + Text("削除") + } + .tint(.red) + Button { + self.tagTargetSlug = tag.slug + self.tagNewName = tag.name + self.showedUpdateTagDialog = true + } label: { + Text("変更") + } + .tint(.green) + } + + } + } + .listStyle(.plain) + .searchable(text: $filterText, prompt: "検索キーワード") + .keyboardType(.default) + } + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button(action: { + self.tagNewName = "" + self.showedNewTagDialog = true + }) { + Image(systemName: "plus.app") + } + } + } + .alert("新規登録", isPresented: $showedNewTagDialog) { + NameAlertView(label: "タグ", act: "追加", onOk: allTagsViewModel.createTag) {(message: String) in + self.showedErrorAlert = true + self.errorAlertTitle = message + } + } message: { + Text("タグ名を入力してください") + } + .alert("更新", isPresented: $showedUpdateTagDialog) { + NameAlertView(label: "タグ", act: "変更", input: tagNewName) {(name: String) in allTagsViewModel.updateTag(tagTargetSlug, name) + } onError : {(message: String) in + self.showedErrorAlert = true + self.errorAlertTitle = message + } + } message: { + Text("タグ名を入力してください") + } + .alert(errorAlertTitle, isPresented: $showedErrorAlert, actions: { + Button(action: { + // nop + }, label: { + Text("確認") + }) + }) + } + .sheet(isPresented: $showedLoginView) { + LoginWebView() + .onDisappear { + allTagsViewModel.getAllTags() + } + } + .scrollDismissesKeyboard(.immediately) + .onAppear { + allTagsViewModel.bremerApiBaseUrl = settingViewModel.getSetting().baseApiUrl() + allTagsViewModel.getAllTags() + } + } +} + +struct TagDescView : View { + @EnvironmentObject + var tagAudioViewModel : TagAudioViewModel + @EnvironmentObject + var audioPlayerViewModel : AudioPlayerViewModel + @EnvironmentObject + var settingViewModel : SettingViewModel + @State + var showedDeleteTagDialog = false + @State + var targetAudio : Audio? = nil + var slug : String + + var body : some View { + VStack { + if !tagAudioViewModel.messageText.isEmpty { + if (tagAudioViewModel.hasError) { + VStack { + Text(tagAudioViewModel.messageText) + .foregroundColor(.red) + } + } else { + Text(tagAudioViewModel.messageText) + } + } + List { + ForEach(tagAudioViewModel.result, id:\.slug) { audio in + Button(action: { + audioPlayerViewModel.playAudioList( + audioList: tagAudioViewModel.result, audio: audio, usedBy: "tag") + }) { + Text("\(audio.name) - \(audio.album ?? "")") + .font(.system(size: 14)) + .frame(height: 35, alignment: .center) + .aspectRatio(contentMode: .fit) + } + .swipeActions(edge: .trailing) { + Button { + // TODO 再生中の時は削除する必要ある + self.tagAudioViewModel.deleteAudioInTag(tagSlug: slug, audio: audio) + } label: { + Text("削除") + } + .tint(.red) + } + } + } + .listStyle(.plain) + .keyboardType(.default) + Spacer() + Divider() + AudioPlayerView(audioPlayerViewModel: audioPlayerViewModel) + } + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + NavigationLink(destination: TagAddView(slug: slug)){ + Image(systemName: "plus.app") + } + } + } + .onAppear { + self.tagAudioViewModel.bremerApiBaseUrl = settingViewModel.getSetting().baseApiUrl() + self.tagAudioViewModel.getAllAudio(slug: slug) + } + } +} + +struct TagAddView : View { + @State + var slug : String + @State + private var searchText : String = "" + @State + private var toastMessage = "" + @State + private var audioInfo = AudioInfo() + @State + private var audioTargetSlug = "" + @State + private var showedToast = false + @State + private var showedSearchAudioDialog = false + @State + private var showedLoginView = false + @State + private var showedUpdateAudioDialog = false + @State + private var showedErrorAlert = false + @State + private var errorAlertTitle = "" + @EnvironmentObject + private var tagAudioViewModel : TagAudioViewModel + @EnvironmentObject + private var audioPlayerViewModel : AudioPlayerViewModel + @EnvironmentObject + private var searchAudioViewModel : SearchAudioViewModel + @EnvironmentObject + private var configViewModel : SettingViewModel + + var body : some View { + NavigationView { + ZStack { + VStack { + if !searchAudioViewModel.messageText.isEmpty { + if (searchAudioViewModel.hasError) { + VStack { + Text(searchAudioViewModel.messageText) + .foregroundColor(.red) + LoginButton(action: { + self.showedLoginView = true + }) + } + } else { + Text(searchAudioViewModel.messageText) + } + } + List { + ForEach(searchAudioViewModel.result, id:\.slug) { audio in + HStack { + Button(action: { + audioPlayerViewModel.playAudioList( + audioList: [audio], audio: audio, usedBy: "playlist-add") + }) { + Text("\(audio.name) - \(audio.album ?? "")") + .font(.system(size: 14)) + .frame(height: 35, alignment: .center) + .aspectRatio(contentMode: .fit) + } + .buttonStyle(PlainButtonStyle()) + Spacer() + Button(action: { + tagAudioViewModel.addAudio(tagSlug:slug, audio: audio) + audioPlayerViewModel.addAudio(audio: audio, usedBy: "tag-\(slug)") + self.toastMessage = "\(audio.name) を追加" + self.showedToast = true + }) { + Image(systemName: "plus.app") + .resizable() + .scaledToFill() + .frame(width: 33, height: 33) + } + .buttonStyle(PlainButtonStyle()) + } + .swipeActions(edge: .trailing) { + Button { + self.audioTargetSlug = audio.slug + self.audioInfo.audioName = audio.name + self.audioInfo.artistName = audio.artist ?? "" + self.audioInfo.albumName = audio.album ?? "" + self.audioInfo.localPath = audio.localPath + self.showedUpdateAudioDialog = true + } label: { + Text("変更") + } + .tint(.green) + } + } + } + .listStyle(.plain) + .searchable(text: $searchText, prompt: "検索キーワード") + .onSubmit(of: .search) { + searchAudioViewModel.searchAudio(keyword: searchText) + } + .alert("更新", isPresented: $showedUpdateAudioDialog) { + RenameAudioAlertView(audioInfo: self.audioInfo) {(audioInfo: AudioInfo) in + searchAudioViewModel.updateAudio( + slug: audioTargetSlug, + audioName: audioInfo.audioName, + artistName: audioInfo.artistName, + albumName: audioInfo.albumName) + } onError: {(message: String) in + self.errorAlertTitle = message + self.showedErrorAlert = true + } + } message: { + Text("新しい名前を入力してください") + } + } + if showedToast { + VStack { + Spacer() + ToastView(message: toastMessage) + } + .onAppear(perform: { + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + withAnimation { + self.showedToast = false + } + } + }) + } + } + } + .sheet(isPresented: $showedLoginView) { + LoginWebView() + } + .scrollDismissesKeyboard(.immediately) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button(action: { + self.showedSearchAudioDialog = true + }) { + Image(systemName: "text.magnifyingglass") + } + } + } + .alert("詳細検索", isPresented: $showedSearchAudioDialog) { + SearchDetailAlertView(searchAction: searchAudioViewModel.searchAudio) + } message: { + Text("新しい名前を入力してください") + } + .onAppear { + searchAudioViewModel.bremerApiBaseUrl = configViewModel.getSetting().baseApiUrl() + searchAudioViewModel.result = [] + } + } +} diff --git a/BremerApp/ViewModel/AllPlaylistViewModel.swift b/BremerApp/ViewModel/AllPlaylistViewModel.swift new file mode 100644 index 0000000..c145937 --- /dev/null +++ b/BremerApp/ViewModel/AllPlaylistViewModel.swift @@ -0,0 +1,109 @@ +// +// AllPlaylistViewModel.swift +// Bremer +// +// Created by yhornisse on 2023/08/08. +// + +import Combine +import Foundation + +public final class AllPlaylistViewModel : ObservableObject { + @Published + var playlists: [Playlist] = [] + @Published + var hasError = false + @Published + var messageText : String = "" + @Published + var disposables = [AnyCancellable]() + @Published + var bremerApiBaseUrl = "" + + func getAllPlaylist() { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/playlist" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + self.playlists = [] + } + } receiveValue: { (response : AllPlaylistApiResponse) in + self.playlists = response.playlist + if (self.playlists.isEmpty) { + self.hasError = false + self.messageText = "プレイリストがありません" + } else { + self.hasError = false + self.messageText = "" + } + } + .store(in: &disposables) + } + + func createPlaylist(_ name: String) { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/playlist" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "POST", + requestBody: PlaylistRequest(name: name)) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + self.getAllPlaylist() + } + .store(in: &disposables) + } + + func updatePlaylist(_ slug: String, _ name: String) { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/playlist/\(slug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "PUT", + requestBody: PlaylistRequest(name: name)) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + self.getAllPlaylist() + } + .store(in: &disposables) + } + + func deletePlaylist(_ slug: String) { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/playlist/\(slug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "DELETE") + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + self.getAllPlaylist() + } + .store(in: &disposables) + } +} diff --git a/BremerApp/ViewModel/AllTagsViewModel.swift b/BremerApp/ViewModel/AllTagsViewModel.swift new file mode 100644 index 0000000..eede9a7 --- /dev/null +++ b/BremerApp/ViewModel/AllTagsViewModel.swift @@ -0,0 +1,109 @@ +// +// AllTagsViewModel.swift +// Bremer +// +// Created by yhornisse on 2023/08/23. +// + +import Combine +import Foundation + +public final class AllTagsViewModel : ObservableObject { + @Published + var tags: [Tag] = [] + @Published + var hasError = false + @Published + var messageText : String = "" + @Published + var disposables = [AnyCancellable]() + @Published + var bremerApiBaseUrl = "" + + func getAllTags() { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/tag" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + self.tags = [] + } + } receiveValue: { (response : AllTagsApiResponse) in + self.tags = response.tags + if (self.tags.isEmpty) { + self.hasError = false + self.messageText = "タグがありません" + } else { + self.hasError = false + self.messageText = "" + } + } + .store(in: &disposables) + } + + func createTag(_ name: String) { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/tag" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "POST", + requestBody: TagRequest(name: name)) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + self.getAllTags() + } + .store(in: &disposables) + } + + func updateTag(_ slug: String, _ name: String) { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/tag/\(slug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "PUT", + requestBody: TagRequest(name: name)) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + self.getAllTags() + } + .store(in: &disposables) + } + + func deleteTag(_ slug: String) { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/tag/\(slug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "DELETE") + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + self.getAllTags() + } + .store(in: &disposables) + } +} diff --git a/BremerApp/ViewModel/AudioPlayerViewModel.swift b/BremerApp/ViewModel/AudioPlayerViewModel.swift new file mode 100644 index 0000000..870d5b9 --- /dev/null +++ b/BremerApp/ViewModel/AudioPlayerViewModel.swift @@ -0,0 +1,343 @@ +// +// ContentView.swift +// Bremer +// +// Created by yhornisse on 2023/05/06. +// + +import MediaPlayer +import AVFoundation +import Combine + +public class AudioPlayerViewModel : NSObject, AVAudioPlayerDelegate, ObservableObject { + + var musicPlayer : AVAudioPlayer? = nil + var audioQueue : [Audio] = [] + private var audioFileCache : Dictionary = [:] // slug -> URL + @Published + var playingMusic : Audio? = nil + @Published + var isPlaying = false + private var maxSize = 4 + @Published + private var audioList : [Audio] = [] + @Published + private var errorText : String = "" + @Published + private var usedBy = "" + @Published + private var hasError = false + @Published + private var messageText = "" + @Published + private var bremerApiBaseUrl = "" + private var disposables = [AnyCancellable]() + + func onInterrupted(_ notification: Notification) { + guard let userInfo = notification.userInfo, + let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt, + let type = AVAudioSession.InterruptionType(rawValue: typeValue) else { + return + } + switch type { + case .began: + if isPlaying { + pauseAudio() + } + break + case .ended: + if !isPlaying { + playAudio() + } + break + @unknown default: + break + } + } + + func onChangeAudioSessionRoute(_ notification: Notification) { + guard let userInfo = notification.userInfo, + let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt, + let reason = AVAudioSession.RouteChangeReason(rawValue:reasonValue) else { + return + } + switch reason { + case .newDeviceAvailable: + if !isPlaying { + playAudio() + } + case .oldDeviceUnavailable: + if isPlaying { + pauseAudio() + } + default: + break + } + } + + func setupAudioPlayer() { + // MPRemoteCommandCenter + let commandCenter = MPRemoteCommandCenter.shared() + commandCenter.playCommand.isEnabled = true + commandCenter.playCommand.addTarget { [unowned self] event in + self.isPlaying = true + musicPlayer?.play() + return .success + } + commandCenter.pauseCommand.isEnabled = true + commandCenter.pauseCommand.addTarget { [unowned self] event in + self.isPlaying = false + musicPlayer?.stop() + return .success + } + // MPNowPlayingInfoCenter + var nowPlayingInfo: [String: Any] = MPNowPlayingInfoCenter.default().nowPlayingInfo ?? [:] + if let audio = self.playingMusic { + nowPlayingInfo[MPMediaItemPropertyTitle] = "\(audio.name) - \(audio.album ?? "")" + nowPlayingInfo[MPMediaItemPropertyArtist] = audio.artist ?? "" + } + nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = "1" + if let duration = self.musicPlayer?.duration { + nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = duration + } + MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo + // etc + do { + try AVAudioSession.sharedInstance() + .setCategory(.playAndRecord, options: [.defaultToSpeaker, + .allowAirPlay, + .allowBluetoothA2DP]) + try AVAudioSession.sharedInstance().setActive(true) + } catch { + // TODO 後から直す + print(error.localizedDescription) + } + // on Stop a music + self.musicPlayer?.delegate = self + } + + func downloadAudio(audio:Audio, onDownload:(() -> Void)?) { + if let location = self.audioFileCache[audio.slug] + , FileManager.default.fileExists(atPath: location.path) { + if let onDownload = onDownload { + onDownload() + return + } + } + let cookie = UserDefaults.standard.string(forKey: "JSESSIONID") + if cookie == nil { + errorText = "Connection Error!" + return + } + var request:URLRequest = URLRequest(url: URL(string: "https://pied-piper.net/bremer/audio/\(audio.slug)")!) + request.setValue("JSESSIONID=\(cookie!)", forHTTPHeaderField: "Cookie") + URLSession.shared.downloadTask(with: request) { (location, response, error) in + if error != nil { + self.errorText = "Download Error!" + return + } + + do { + if let location = location { + if self.audioFileCache.count >= self.maxSize { + if let lrpAudio = self.audioQueue.first { + self.audioQueue.removeFirst() + if let lrpFileLocation = self.audioFileCache[lrpAudio.slug] { + self.audioFileCache.removeValue(forKey: lrpAudio.slug) + do { + if FileManager.default.fileExists(atPath: lrpFileLocation.path) { + try FileManager.default.removeItem(atPath: lrpFileLocation.path) + } + } catch { + // TODO print 以外にする + print(error.localizedDescription) + } + } + } + } + if !self.audioQueue.contains(where: { $0.slug == audio.slug }) { + self.audioQueue.append(audio) + } + let file = FileManager.default.temporaryDirectory + .appendingPathComponent(UUID().uuidString) + .appendingPathExtension("tmp") + try FileManager.default.copyItem( + at: location, + to: file + ) + self.audioFileCache[audio.slug] = file + if let onDownload = onDownload { + onDownload() + } + } + } catch { + print(error.localizedDescription) + } + } + .resume() + } + + func play(audio:Audio) -> Bool { + if !self.audioFileCache.keys.contains(audio.slug) { + return false + } + + if self.musicPlayer?.isPlaying == true { + self.isPlaying = false + self.musicPlayer?.stop() + } + do { + setupAudioPlayer() + if let audioFile = self.audioFileCache[audio.slug] { + if FileManager.default.fileExists(atPath: audioFile.path) { + if self.musicPlayer?.isPlaying == true { + self.isPlaying = false + self.musicPlayer?.stop() + } + if let queueIdx = self.audioQueue.firstIndex(where: { $0.slug == audio.slug }) { + self.audioQueue.remove(at: queueIdx) + self.audioQueue.append(audio) + } + self.playingMusic = audio + self.musicPlayer = try AVAudioPlayer(contentsOf: audioFile) + self.setupAudioPlayer() + self.musicPlayer?.play() + self.isPlaying = true + sendApi(url: URL(string: "\(bremerApiBaseUrl)/audio/history/\(audio.slug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "POST") + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + switch (error) { + case is BremerConnectionError: + self.hasError = true + self.messageText = "Connection error" + break + default: + self.hasError = true + self.messageText = error.localizedDescription + } + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + } + .store(in: &disposables) + return true; + } + } + } catch { + // TODO 後から直す + print(error.localizedDescription) + } + return false + } + + + func playAudio() { + self.isPlaying = true + self.musicPlayer?.play() + } + + func pauseAudio() { + self.isPlaying = false + self.musicPlayer?.pause() + } + + func setAudioSeq(seq : Double) { + self.musicPlayer?.currentTime = seq + } + + func musicTime() -> String { + let a = Int(musicPlayer?.currentTime ?? 0.0) + let b = Int(musicPlayer?.duration ?? 0.0) + return "\(String(format: "%02d", a / 60)):\(String(format: "%02d", a % 60)) / \(String(format: "%02d", b / 60)):\(String(format: "%02d", b % 60))" + } + + func musicTimeRate() -> Double { + let a = musicPlayer?.currentTime ?? 0.0 + let b = musicPlayer?.duration ?? 0.0 + return a / b + } + + func playAudio(idx: Int) { + if idx >= audioList.count { + return + } + let audio = audioList[idx] + if self.play(audio: audio) { + return; + } + + downloadAudio(audio: audio, onDownload: { + self.play(audio: audio) + }) + } + + func playAudioList(audioList: [Audio], audio: Audio, usedBy: String) { + self.usedBy = usedBy + self.audioList = audioList + if let idx = self.audioList.firstIndex(where: { $0.slug == audio.slug }) { + self.playAudio(idx: idx) + self.prefetch(idx: idx) + } + } + + func playAudio(audio: Audio) { + if let idx = self.audioList.firstIndex(where: { $0.slug == audio.slug }) { + self.playAudio(idx: idx) + self.prefetch(idx: idx) + } + } + + func reorderAudioList(from: IndexSet, to: Int, usedBy: String) { + if self.usedBy != usedBy { + return + } + if to < self.audioList.count { + self.audioList.move(fromOffsets: from, toOffset: to) + } else { + self.audioList.move(fromOffsets: from, toOffset: self.audioList.count - 1) + } + } + + func addAudio(audio: Audio, usedBy: String) { + if self.usedBy != usedBy { + return + } + if self.audioList.contains(where: { $0.slug == audio.slug }) == true { + return + } + self.audioList.append(audio) + } + + public func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { + self.isPlaying = false + if let slug = self.playingMusic?.slug { + if let idx = self.audioList.firstIndex(where: { $0.slug == slug }) { + if idx + 1 < self.audioList.count { + playAudio(idx: idx + 1) + prefetch(idx: idx + 1) + } + } + } + } + + func prefetch(idx: Int) { + if idx + 1 < self.audioList.count { + self.downloadAudio(audio: self.audioList[idx + 1], onDownload: nil) + } + } + + func exists(_ slug: String) -> Bool { + if let location = self.audioFileCache[slug], + FileManager.default.fileExists(atPath: location.path) { + return true + } else { + return false + } + } +} diff --git a/BremerApp/ViewModel/BremerApi.swift b/BremerApp/ViewModel/BremerApi.swift new file mode 100644 index 0000000..ec85434 --- /dev/null +++ b/BremerApp/ViewModel/BremerApi.swift @@ -0,0 +1,112 @@ +// +// RemoteAudioService.swift +// Bremer +// +// Created by yhornisse on 2023/07/17. +// + +import Combine +import Foundation + +public func getApiFailureTextByError(_ error: Error) -> String { + switch (error) { + case is BremerLoginError: + return "ログインしてください" + case is BremerConnectionError: + return "Connection error" + default: + return error.localizedDescription + } +} + +public func sendApi(url: URL) -> AnyPublisher { + let cookie = UserDefaults.standard.string(forKey: "JSESSIONID") + if cookie == nil { + return Future { promise in + promise(.failure(BremerConnectionError())) + }.eraseToAnyPublisher() + } + var request:URLRequest = URLRequest(url: url) + request.setValue("JSESSIONID=\(cookie!)", forHTTPHeaderField: "Cookie") + request.addValue("application/json", forHTTPHeaderField: "Content-Type") + let jsonDecoder = JSONDecoder() + jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase + return URLSession.shared.dataTaskPublisher(for: request) + .tryMap { res in + guard let httpResponse = res.response as? HTTPURLResponse, httpResponse.statusCode == 200 else { + throw BremerConnectionError() + } + guard let mimeType = httpResponse.mimeType else { + throw BremerConnectionError() + } + if mimeType == "text/html" { + guard let url = httpResponse.url else { + throw BremerConnectionError() + } + if url.path == "/bremer/login.html" { + throw BremerLoginError() + } + } + return res.data + } + .decode(type: T.self, decoder: jsonDecoder) + .receive(on: DispatchQueue.main) + .eraseToAnyPublisher() +} + + +public func sendApi(url: URL, httpMethod: String) -> AnyPublisher { + let cookie = UserDefaults.standard.string(forKey: "JSESSIONID") + if cookie == nil { + return Future { promise in + promise(.failure(BremerConnectionError())) + }.eraseToAnyPublisher() + } + var request:URLRequest = URLRequest(url: url) + request.httpMethod = httpMethod + request.setValue("JSESSIONID=\(cookie!)", forHTTPHeaderField: "Cookie") + request.addValue("application/json", forHTTPHeaderField: "Content-Type") + let jsonDecoder = JSONDecoder() + jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase + return URLSession.shared.dataTaskPublisher(for: request) + .tryMap { res in + guard let httpResponse = res.response as? HTTPURLResponse, httpResponse.statusCode == 200 else { + throw BremerConnectionError() + } + return res + } + .receive(on: DispatchQueue.main) + .eraseToAnyPublisher() +} + +public func sendApi(url: URL, httpMethod: String, requestBody: U) -> AnyPublisher { + let cookie = UserDefaults.standard.string(forKey: "JSESSIONID") + if cookie == nil { + return Future { promise in + promise(.failure(BremerConnectionError())) + }.eraseToAnyPublisher() + } + var request:URLRequest = URLRequest(url: url) + request.httpMethod = httpMethod + request.setValue("JSESSIONID=\(cookie!)", forHTTPHeaderField: "Cookie") + request.addValue("application/json", forHTTPHeaderField: "Content-Type") + do { + let jsonEncoder = JSONEncoder() + jsonEncoder.keyEncodingStrategy = .convertToSnakeCase + request.httpBody = try jsonEncoder.encode(requestBody) + } catch { + // TODO あとで例外書く + print("エラー") + } + let jsonDecoder = JSONDecoder() + jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase + return URLSession.shared.dataTaskPublisher(for: request) + .tryMap { res in + guard let httpResponse = res.response as? HTTPURLResponse, httpResponse.statusCode == 200 else { + throw BremerConnectionError() + } + return res + } + .receive(on: DispatchQueue.main) + .eraseToAnyPublisher() +} diff --git a/BremerApp/ViewModel/LatestRecentlyPlayedAudioViewModel.swift b/BremerApp/ViewModel/LatestRecentlyPlayedAudioViewModel.swift new file mode 100644 index 0000000..37f0767 --- /dev/null +++ b/BremerApp/ViewModel/LatestRecentlyPlayedAudioViewModel.swift @@ -0,0 +1,69 @@ +// +// LatestRecentlyPlayedAudioViewModel.swift +// Bremer +// +// Created by yhornisse on 2023/08/22. +// + +import Combine +import Foundation + +public final class LatestRecentlyPlayedAudioViewModel : ObservableObject { + + @Published + var result : [Audio] = [] + @Published + var hasError = false + @Published + var messageText : String = "" + @Published + var bremerApiBaseUrl = "" + @Published + var disposables = [AnyCancellable]() + + func getAllAudio() { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/audio/history" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + self.result = [] + } + } receiveValue: { (response : AudioApiResponse) in + self.result = response.audioList + if (self.result.isEmpty) { + self.hasError = false + self.messageText = "再生する曲がありません" + } else { + self.hasError = false + self.messageText = "" + } + } + .store(in: &disposables) + } + + func updateAudio(slug:String, audioName:String, artistName:String, albumName:String) { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/audio/\(slug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "PUT", + requestBody: AudioRequest(name: audioName, artist: artistName, album: albumName)) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + } + .store(in: &disposables) + } +} + diff --git a/BremerApp/ViewModel/PlaylistAudioViewModel.swift b/BremerApp/ViewModel/PlaylistAudioViewModel.swift new file mode 100644 index 0000000..495747e --- /dev/null +++ b/BremerApp/ViewModel/PlaylistAudioViewModel.swift @@ -0,0 +1,89 @@ +// +// PlaylistViewModel.swift +// Bremer +// +// Created by yhornisse on 2023/08/22. +// + +import Combine +import Foundation + +public final class PlaylistAudioViewModel : ObservableObject { + + @Published + private var playlistName : String = "" + @Published + var hasError = false + @Published + var messageText : String = "" + @Published + var result : [Audio] = [] + @Published + var bremerApiBaseUrl = "" + @Published + var disposables = [AnyCancellable]() + + func getAllAudio(slug: String) { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/playlist/\(slug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + self.result = [] + } + } receiveValue: { (response : PlaylistApiResponse) in + self.playlistName = response.name + self.result = response.audioList + if (self.result.isEmpty) { + self.hasError = false + self.messageText = "再生する曲がありません" + } else { + self.hasError = false + self.messageText = "" + } + } + .store(in: &disposables) + } + + func save(slug: String) { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/playlist/audio/\(slug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "PUT", + requestBody: PlaylistAudioRequest(audioSlugs: result.map{ $0.slug })) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + } + .store(in: &disposables) + } + + func reorderPlaylist(from: IndexSet, to: Int) { + self.result.move(fromOffsets: from, toOffset: to) + } + + func deleteAudioInPlaylist(playlistSlug: String, audioSlug: String) { + self.result.removeAll(where: { $0.slug == audioSlug }) + self.save(slug: playlistSlug) + } + + func addAudio(audio: Audio) { + if self.result.contains(where: { $0.slug == audio.slug }) == true { + print("登録済み") + return + } + self.result.append(audio) + } +} + diff --git a/BremerApp/ViewModel/SearchAudioViewModel.swift b/BremerApp/ViewModel/SearchAudioViewModel.swift new file mode 100644 index 0000000..3d0127f --- /dev/null +++ b/BremerApp/ViewModel/SearchAudioViewModel.swift @@ -0,0 +1,112 @@ +// +// SearchAudioViewModel.swift +// Bremer +// +// Created by yhornisse on 2023/08/22. +// + +import Combine +import Foundation + +public class AudioInfo { + var slug = "" + var audioName = "" + var artistName = "" + var albumName = "" + var localPath = "" +} + +public class SearchAudioViewModel : ObservableObject { + + @Published + private var audio = "" + @Published + private var artist = "" + @Published + private var album = "" + @Published + private var tag = "" + @Published + var hasError = false + @Published + var messageText : String = "" + @Published + var result : [Audio] = [] + @Published + var bremerApiBaseUrl = "" + @Published + var disposables = [AnyCancellable]() + + func searchAudio(keyword: String) { + searchAudio(audio: keyword, artist: keyword, album: keyword, tag: keyword) + } + + func searchAudio(audio: String, artist:String, album:String, tag:String) { + self.audio = audio + self.artist = artist + self.album = album + self.tag = tag + sendApi(url: URL(string: "\(bremerApiBaseUrl)/audio?audio=\(audio)&album=\(album)&artist=\(artist)&tag=\(tag)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + self.result = [] + } + } receiveValue: { (response : AudioApiResponse) in + self.result = response.audioList + if (self.result.isEmpty) { + self.hasError = false + self.messageText = "一致する曲がありません" + } else { + self.hasError = false + self.messageText = "" + self.searchAudio(audio: self.audio, artist: self.artist, album: self.album, tag: self.tag) + } + } + .store(in: &disposables) + } + + func updateAudio(slug:String, audioName:String, artistName:String, albumName:String) { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/audio/\(slug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "PUT", + requestBody: AudioRequest(name: audioName, artist: artistName, album: albumName)) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + } + .store(in: &disposables) + } + + func deleteAudio(_ slug:String) { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/audio/\(slug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "DELETE") + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + } + .store(in: &disposables) + } +} diff --git a/BremerApp/ViewModel/SettingViewModel.swift b/BremerApp/ViewModel/SettingViewModel.swift new file mode 100644 index 0000000..0644912 --- /dev/null +++ b/BremerApp/ViewModel/SettingViewModel.swift @@ -0,0 +1,46 @@ +// +// SettingViewModel.swift +// Bremer +// +// Created by yhornisse on 2023/08/26. +// + +import Foundation +import RealmSwift + +class BremerSetting: Object { + @objc dynamic var id = 0 + @objc dynamic var baseUrl = "" + override static func primaryKey() -> String? { + return "id" + } + func baseApiUrl() -> String { + return "\(baseUrl)/api" + } +} + +public class SettingViewModel : ObservableObject { + let realm = try! Realm() + + func updateBaseApiUrl(_ baseApiUrl: String) { + let setting = BremerSetting() + setting.baseUrl = baseApiUrl + let results = realm.objects(BremerSetting.self) + try! realm.write { + if results.isEmpty { + realm.add(setting) + } else { + realm.add(setting, update: .modified) + } + } + } + + func getSetting() -> BremerSetting { + let results = realm.objects(BremerSetting.self) + if results.isEmpty { + return BremerSetting() + } else { + return results[0] + } + } +} diff --git a/BremerApp/ViewModel/TagAudioViewModel.swift b/BremerApp/ViewModel/TagAudioViewModel.swift new file mode 100644 index 0000000..0975479 --- /dev/null +++ b/BremerApp/ViewModel/TagAudioViewModel.swift @@ -0,0 +1,110 @@ +// +// AllTagsViewModel.swift +// Bremer +// +// Created by yhornisse on 2023/08/22. +// + +import Combine +import Foundation + +public final class TagAudioViewModel : ObservableObject { + + @Published + private var playlistName : String = "" + @Published + var hasError = false + @Published + var messageText : String = "" + @Published + var result : [Audio] = [] + @Published + var disposables = [AnyCancellable]() + @Published + var bremerApiBaseUrl = "" + + func getAllAudio(slug: String) { + sendApi(url: URL(string: "\(bremerApiBaseUrl)/tag/\(slug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + switch (error) { + case is BremerLoginError: + self.hasError = true + self.messageText = "Login error" + case is BremerConnectionError: + self.hasError = true + self.messageText = "Connection error" + default: + self.hasError = true + self.messageText = error.localizedDescription + } + self.result = [] + } + } receiveValue: { (response : TagApiResponse) in + self.playlistName = response.name + self.result = response.audioList + if (self.result.isEmpty) { + self.hasError = false + self.messageText = "再生する曲がありません" + } else { + self.hasError = false + self.messageText = "" + } + } + .store(in: &disposables) + } + + func addAudio(tagSlug: String, audio: Audio) { + if self.result.contains(where: { $0.slug == audio.slug }) == true { + print("登録済み") + return + } + self.result.append(audio) + sendApi(url: URL(string: "\(bremerApiBaseUrl)/tag/audio/\(tagSlug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "POST", + requestBody: TagAudioRequest(audioSlugs: [audio.slug])) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + } + .store(in: &disposables) + } + + func reorderPlaylist(from: IndexSet, to: Int) { + self.result.move(fromOffsets: from, toOffset: to) + } + + func deleteAudioInTag(tagSlug: String, audio: Audio) { + self.result.removeAll(where: { $0.slug == audio.slug }) + sendApi(url: URL(string: "\(bremerApiBaseUrl)/tag/audio/\(tagSlug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, + httpMethod: "DELETE", + requestBody: TagAudioRequest(audioSlugs: [audio.slug])) + .sink { completion in + switch completion { + case .finished: + break + case .failure(let error): + self.hasError = true + self.messageText = getApiFailureTextByError(error) + } + } receiveValue: { (response : Any) in + self.hasError = false + self.messageText = "" + } + .store(in: &disposables) + } +} diff --git a/Podfile b/Podfile new file mode 100644 index 0000000..7a39a3e --- /dev/null +++ b/Podfile @@ -0,0 +1,21 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '9.0' + +target 'Bremer' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Pods for Bremer + + pod 'RealmSwift' + + target 'BremerTests' do + inherit! :search_paths + # Pods for testing + end + + target 'BremerUITests' do + # Pods for testing + end + +end diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..d1f3fdc --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,22 @@ +PODS: + - Realm (10.42.0): + - Realm/Headers (= 10.42.0) + - Realm/Headers (10.42.0) + - RealmSwift (10.42.0): + - Realm (= 10.42.0) + +DEPENDENCIES: + - RealmSwift + +SPEC REPOS: + trunk: + - Realm + - RealmSwift + +SPEC CHECKSUMS: + Realm: 490aad28f1360e58fc22256d5d686d3a36525346 + RealmSwift: f6a9b56d747bbdd7931de1835896c5f024b6898a + +PODFILE CHECKSUM: 139d0def1eeea9f85f6efea446ccf05baa831703 + +COCOAPODS: 1.12.1 diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock new file mode 100644 index 0000000..d1f3fdc --- /dev/null +++ b/Pods/Manifest.lock @@ -0,0 +1,22 @@ +PODS: + - Realm (10.42.0): + - Realm/Headers (= 10.42.0) + - Realm/Headers (10.42.0) + - RealmSwift (10.42.0): + - Realm (= 10.42.0) + +DEPENDENCIES: + - RealmSwift + +SPEC REPOS: + trunk: + - Realm + - RealmSwift + +SPEC CHECKSUMS: + Realm: 490aad28f1360e58fc22256d5d686d3a36525346 + RealmSwift: f6a9b56d747bbdd7931de1835896c5f024b6898a + +PODFILE CHECKSUM: 139d0def1eeea9f85f6efea446ccf05baa831703 + +COCOAPODS: 1.12.1 diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..2aa41b2 --- /dev/null +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,2180 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 00D2EA50D76FE77C68B05C6174F0E50D /* RLMObjectSchema.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = D0A8A01C6E0F577E45980964BB353E35 /* RLMObjectSchema.h */; }; + 0164F3A05EF99C22264D6A0806AB4E6C /* RLMSwiftCollectionBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 8096A6CE2B47313736FA293317A1947C /* RLMSwiftCollectionBase.h */; }; + 01BD2BEAB90425EBA4BDB2489136B27B /* RLMUser.h in Headers */ = {isa = PBXBuildFile; fileRef = 6983861E2027D12D1EE3509BFA276CDC /* RLMUser.h */; }; + 02A9BD5CFEF8CF5CDE82D5F3C99595A1 /* RLMObjectStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 287A198FE10ED2E080F841D672EEB650 /* RLMObjectStore.h */; }; + 03CFFAB7B53DCDF2AB6C216E304C9846 /* RLMLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 97ACC83057F43D9B6980F6F7C750B9DF /* RLMLogger.h */; }; + 03FF5CF0BBF8F4C1C997DAA2C73495AF /* RLMUser.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6446CF5660FCF90AA0617D6B16C9B7E2 /* RLMUser.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 0442CEDEA4243DD8629F664272A285DE /* KeyPathStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FD6D5AC2A4EDD998FDAE19520FB6DA8 /* KeyPathStrings.swift */; }; + 04D7A62FC4D8A761493E347FF1788FDF /* RLMEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 5AA3DBC5397A141FB8A3B336E0C3CA72 /* RLMEvent.h */; }; + 0593AF2DD216BD5C78A89C94561EB0BD /* RLMManagedArray.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8F40C24E83BF14942C1ECD9977BED25A /* RLMManagedArray.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 05EC68A60F14F305F3AF79F800F133C3 /* RLMError.h in Headers */ = {isa = PBXBuildFile; fileRef = DC906F177DFF762E0F2E2A4095889CFE /* RLMError.h */; }; + 06304E80795DA749417F68A31C6A4D74 /* Results.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E72B23F2A49F29F16A02EFFA295F479 /* Results.swift */; }; + 06358E068A2C99AE81BD71D78017CA21 /* RLMEmailPasswordAuth.h in Headers */ = {isa = PBXBuildFile; fileRef = 3242E2AFF0DE901E8DB25964E6FCA10E /* RLMEmailPasswordAuth.h */; }; + 071AAAAA27F2BFD0E44D86939213CC91 /* RLMObjectBase.mm in Sources */ = {isa = PBXBuildFile; fileRef = B74909372FE229B46DB6568F865259B3 /* RLMObjectBase.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 07F261922769AA1165299B51787D22D6 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C86ED21C9DEA623DAFDDF386C44A42 /* Query.swift */; }; + 0A6750B00EA3B3674F044F5FDF5D5AD5 /* RLMUpdateResult.mm in Sources */ = {isa = PBXBuildFile; fileRef = DF207A2F226C16092CB5DB8515FC4F50 /* RLMUpdateResult.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 0B084A2ED53F30E3F5C91705620FC5AB /* RLMAsyncTask_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = AF06966964C0E0BF8DDBC044F35434E6 /* RLMAsyncTask_Private.h */; }; + 0B3B59A97C85AE1077DAA6BBCA438998 /* RLMProperty_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 6925048E7FF653A3F7FDA6C80603546F /* RLMProperty_Private.h */; }; + 0D6C52E690487D298703BC1EAA63C0B3 /* RLMUser.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 6983861E2027D12D1EE3509BFA276CDC /* RLMUser.h */; }; + 0E779035800C6FBBF72F017D0C510DF9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 952925E838A0DE4D7BDC4EE54022633D /* Foundation.framework */; }; + 0E7A97BD7EA7026B0879CAAD82C7BC9A /* RLMAsymmetricObject.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 15AFE66B86114D491B00DFE510CC6081 /* RLMAsymmetricObject.h */; }; + 0EDF63B3A2C61F94E8716B73FABA19C2 /* RLMObjectBase_Dynamic.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 0F6AE9474A96853A8CCEB7217E7882B1 /* RLMObjectBase_Dynamic.h */; }; + 0F66BB0F0515C22CF07887AD73317FC7 /* RLMDictionary_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 72CC1F1C755FBC3CF1BAA38D53EE2BE1 /* RLMDictionary_Private.h */; }; + 0FBB768B02824170DF603676989A63D2 /* RLMSyncConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = A9C89270B39D91E8A818E34F32C7799A /* RLMSyncConfiguration.h */; }; + 1059F6E4C81D4442F9A0443E56682D22 /* RealmConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C04C9768E31A75ACAEE02BD5B6CC754 /* RealmConfiguration.swift */; }; + 117A753CAB61836303AD4FAE1513D581 /* RLMAsyncTask_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = AF06966964C0E0BF8DDBC044F35434E6 /* RLMAsyncTask_Private.h */; }; + 1264261A2DE5E83DFAC6D96FDE9A17D9 /* Realm.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = FE8350F6C1FADE55F9BF782D08FDABFD /* Realm.h */; }; + 127D768C00E02D0644E825FED6D4A8AD /* RLMObjectStore.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 287A198FE10ED2E080F841D672EEB650 /* RLMObjectStore.h */; }; + 13281771BE43BAF65031D19E8CCFC5FB /* RLMObjectStore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 695219F6ABA376C2FD4EDABC626FA786 /* RLMObjectStore.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 13B5FCEFE1051075D694B06BD6345BB2 /* Persistable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFEE93CEA5E067B5DCFE4B87C2F14B73 /* Persistable.swift */; }; + 148B5987885C44A9CCA6440E526AB8DB /* RLMSwiftCollectionBase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4C09B309CFB80885122EC89B6624AA54 /* RLMSwiftCollectionBase.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 163BE3484DDE34A40D0A16522F394367 /* RLMAsyncTask.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 4D53E2B9DA57CF465830EC92CE38FEA7 /* RLMAsyncTask.h */; }; + 17A47338450241D6C0BCD42C9B9FDFF0 /* Pods-Bremer-BremerUITests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B300F080FDE47388D3EB31854C9C2C8 /* Pods-Bremer-BremerUITests-dummy.m */; }; + 186A9950AD2BC40A5E06896B3F3FFBC4 /* RealmSwift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 79249BAC9D61B8D7B94CCE8A8E5760C6 /* RealmSwift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 189009C8E5E5CD765B357ED19A6CEE19 /* RLMApp.h in Headers */ = {isa = PBXBuildFile; fileRef = 170BFD8D6212C2BE4613E8915FE93911 /* RLMApp.h */; }; + 189D57C35E8312EF727A1F7F43300B53 /* RLMObjectSchema.h in Headers */ = {isa = PBXBuildFile; fileRef = D0A8A01C6E0F577E45980964BB353E35 /* RLMObjectSchema.h */; }; + 18FA4829DF1DB108BF59C6BFA8DBB690 /* RLMUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = D3468C0BF4B4320A39D25D9CE6584A26 /* RLMUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 1AE31850261F971BBAE81FA9859C5DBE /* SortDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BCC49FB1F90CE18788E9C8DF1F60C9 /* SortDescriptor.swift */; }; + 1BD4BFDCB4734F61ECEFD90BBD45BE97 /* RLMRealm_Dynamic.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 14E5074693C241E739C0F88EA9E26D6E /* RLMRealm_Dynamic.h */; }; + 1C48FF8C98F113D2885F9AC5DC711058 /* RLMCollection.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 53FEC31B25442C280C915CF78B83081E /* RLMCollection.h */; }; + 1CA0567A035870C832DE6060E1C348A1 /* LinkingObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9049A1739CCEC574D7F368AAF96BC20D /* LinkingObjects.swift */; }; + 1E563604E3C43CD98D2CFC150359E536 /* RealmCollectionImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = E07BC5BBA223584E52693AAB962FD0C1 /* RealmCollectionImpl.swift */; }; + 1F59E2EDE8BB7806133ED73D31F1CAE7 /* RLMProviderClient.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = A07078F84B897764F4F56E9E30C2AED9 /* RLMProviderClient.h */; }; + 20C9EB61BF9B4F9E7313447C3DE77402 /* RLMAnalytics.mm in Sources */ = {isa = PBXBuildFile; fileRef = E546E812630FC30731574AD839131FA7 /* RLMAnalytics.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 25288A0E049B582F8B97030FC89F2188 /* NSError+RLMSync.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 5AF7E94666A9B45384AB13E181E4CD57 /* NSError+RLMSync.h */; }; + 252CC3FFD233D0E687BBE6928E710F46 /* RLMAsymmetricObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 15AFE66B86114D491B00DFE510CC6081 /* RLMAsymmetricObject.h */; }; + 25F3F292FF644A128DA6ED70F562BFE6 /* RLMProperty.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 156B0F1647DE46158BC285E80693AC3F /* RLMProperty.h */; }; + 2670A5A2789DA3553D275F63297A52F1 /* RLMEvent.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 5AA3DBC5397A141FB8A3B336E0C3CA72 /* RLMEvent.h */; }; + 27C6414300533AB312AEC4C40CDAA341 /* RLMMongoDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C82009901EC92F1F93D8D4E50B2632 /* RLMMongoDatabase.h */; }; + 287B181CE2842B8EEB1700CCA7CA664E /* RLMValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 656A2602114C6F39008996487E53F025 /* RLMValue.h */; }; + 2949EF413D29DD8D9B589CF18B207330 /* RLMSyncManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF970CC730D7528B9F16B94716554C85 /* RLMSyncManager.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 298946030A825D7750016DCAFEE23039 /* RLMSchema.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 44BE1AE28CD9E51D7A284CB0F4570743 /* RLMSchema.h */; }; + 29C7AB9EE67DB83850C75692523842D4 /* RLMSectionedResults.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = D33AC4A4F700EB53303DA72A42DADD96 /* RLMSectionedResults.h */; }; + 2B1A964A2AF4B39439A8C7B7E3DF1811 /* RLMBSON.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 1936DA062F9BE3920D47A14C3DD4851C /* RLMBSON.h */; }; + 2B2C5BD99F284AB4318D76E496B08D20 /* RLMMongoClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = F37040080B5A487FC968710228E23835 /* RLMMongoClient.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 2BF92AC802D5B4E2D986F41990C81C7A /* RLMSet.h in Headers */ = {isa = PBXBuildFile; fileRef = BA42A0E2BDA802CD41C5791B01D95C8A /* RLMSet.h */; }; + 2C7492344C6598F8514582D5B34F6956 /* ObjectiveCSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E53F66B8F189AD9580AE5C05FB1D28 /* ObjectiveCSupport.swift */; }; + 2CA823A0284D819B4E8F7E23A98D0625 /* RLMSyncSubscription.h in Headers */ = {isa = PBXBuildFile; fileRef = 68D58FC196381235BC49DEF871BC6C4E /* RLMSyncSubscription.h */; }; + 2CAB172C615714D7B24C3E3CB91C8E73 /* Pods-Bremer-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = CB1FDB7543E2546535D25285A7CDCE2C /* Pods-Bremer-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2D451642AC755B81FB7B564B7DA6B871 /* RLMRealmConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 5048457FAC7400CC15E9FF5E34CC736B /* RLMRealmConfiguration.h */; }; + 2D8AC0448C53894AED8E92735A536CD6 /* RLMSwiftValueStorage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3E8354B5E993B479A2BC6DD30FBC6F75 /* RLMSwiftValueStorage.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 2E9DCF5DE252DD97076AFC91842225CF /* AnyRealmValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D84BC124274D8FFAD5233B64FF3CAC3E /* AnyRealmValue.swift */; }; + 2EF91AF0889342D1B81D1DEA288D7415 /* RLMSyncManager.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 0AF05C6D9B63DCA0A6436D62E942292E /* RLMSyncManager.h */; }; + 301E11573A01EEC55F01DD8AF3345675 /* RLMRealm+Sync.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BF652086B82FCB285AF95A331F06874 /* RLMRealm+Sync.h */; }; + 3083EA5E1DB8A69E5D4AA5C14044E6E6 /* RLMSyncConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8309845A98031BE7C80BC7899D47FE76 /* RLMSyncConfiguration.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 30E832A6E54FCBA6BCC6CB16671A697D /* RLMEmailPasswordAuth.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 3242E2AFF0DE901E8DB25964E6FCA10E /* RLMEmailPasswordAuth.h */; }; + 30F9BAC69B2C307C45EEA6EF45302FBC /* RLMSyncSession.mm in Sources */ = {isa = PBXBuildFile; fileRef = 45E82184D579BFB3425818E1CD186CF1 /* RLMSyncSession.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 32C6E8F469B4E195C59FC25D8F4F8C79 /* RLMSchema_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 72BBEB735A09A89265B342D9D00DD130 /* RLMSchema_Private.h */; }; + 33BF9D4F523B37BC98DEFFA47E53D607 /* RLMProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = 156B0F1647DE46158BC285E80693AC3F /* RLMProperty.h */; }; + 33E19DC5B0C4219F9DBA3DA065C3D2D5 /* RLMSwiftCollectionBase.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 8096A6CE2B47313736FA293317A1947C /* RLMSwiftCollectionBase.h */; }; + 33F84AB110CBE7AC7E71C170D50E9D10 /* RLMMongoCollection_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 20F8BD3214B20EF37E8F662ACCAAA60C /* RLMMongoCollection_Private.h */; }; + 34824E3B12CFBDA9EAA9843EFB15B521 /* RLMObservation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2B9DEE7FCD724E8946C81F8A781486E9 /* RLMObservation.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 363350BF63DCB3B5C76A241D02D672FD /* RLMValue.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE989A32E4CB9545DF1C960611306231 /* RLMValue.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 373FC80E5CDAC45384582597687CC60E /* NSError+RLMSync.m in Sources */ = {isa = PBXBuildFile; fileRef = B86B0CF4D89A205EC9854F54BD415F81 /* NSError+RLMSync.m */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 37EC5BBA3E913B89AFE9B8C24303EE69 /* RLMArray.h in Headers */ = {isa = PBXBuildFile; fileRef = F6C1A5EFD84B6A50454D576EA03B4DB4 /* RLMArray.h */; }; + 3852DA002C2FF5588B5F2626BDCB5085 /* RLMEmbeddedObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 1093D1C3E0121F776B90F3F425A05747 /* RLMEmbeddedObject.h */; }; + 39901C4D4268B4A4DCEFFEAAAF86F485 /* RLMLogger_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = AEF5520981A82480A9E8725B47C709F1 /* RLMLogger_Private.h */; }; + 39EA99A31B37C65E005202F18FBB2782 /* Aliases.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78238DD3B0F804A47333BC5B45487E9C /* Aliases.swift */; }; + 3C6886B7C7A89AFEA13AE77D9B52F529 /* RLMMongoCollection.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 7382B395581C4D5173DD3D9F1FA73E6E /* RLMMongoCollection.h */; }; + 3C7C51B018CEE9A67A5C7D5F400A1B21 /* RLMSwiftProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = 98A99A950E295F01B3CE7F2FBBEBC429 /* RLMSwiftProperty.h */; }; + 3D92323EDE4D29026A9374B64C97F9AE /* RLMMigration.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4FD52B51B2909AAB36AD23B0E5C6F4E /* RLMMigration.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 3E036CAA97F279B0C6ABD859726A047A /* CustomPersistable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955AB3E9C7A92CB2C66930D1B7A9F8EE /* CustomPersistable.swift */; }; + 3E1B5386B32268FA87A5B13C81242612 /* Sync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383925AD60D374AAD8AE07ED633D8731 /* Sync.swift */; }; + 3EEB0BAB4684DBA87988BEBEE5A42AD7 /* RLMBSON.h in Headers */ = {isa = PBXBuildFile; fileRef = 1936DA062F9BE3920D47A14C3DD4851C /* RLMBSON.h */; }; + 3EEB5CD0432AE4C966A336FE407F4564 /* SyncSubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDBB744BDFC26FF83B92E27D104894BA /* SyncSubscription.swift */; }; + 3F5DC8E1E4127053A92C72E08D27F5D8 /* BSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71F72372D406C3B51B6B52160127CAFA /* BSON.swift */; }; + 409221ABB1CE39C1A87EE5E10B03225E /* RLMConstants.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 407AB4F6922BDF4346E500A6611B2925 /* RLMConstants.h */; }; + 412DDFCE41F82C3C7947903A74A76034 /* RLMSyncSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C6F253DE442B7CD2596F4212103F666 /* RLMSyncSession.h */; }; + 42606A9EC6B47ACFFCD3795165998394 /* RLMResults.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = E3F27588B6819F964CCE16A4A87A0B84 /* RLMResults.h */; }; + 434FB2F0E1D2A41F940B3FBFF8B4E816 /* RLMScheduler.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 8665FB3F64D1560D6687B39D7E65A68F /* RLMScheduler.h */; }; + 43CD2267C95A4B1EBFE60AD7B3F8E485 /* RLMObject.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = F123E905A47AB485FEE2C2B6188D39A5 /* RLMObject.h */; }; + 4677B933CB1FAF2518CCEE839EDDD168 /* RLMMongoClient.h in Headers */ = {isa = PBXBuildFile; fileRef = A6954DA60DEE09E47284DFB14176FC5C /* RLMMongoClient.h */; }; + 4724AB5CD1E16BBFF664FC2BA7556DBF /* RLMObjectId.h in Headers */ = {isa = PBXBuildFile; fileRef = E003BD497C568C08EC768CD231F1AD26 /* RLMObjectId.h */; }; + 47D4A0C3E2AA44B81CA808C6D939E9B3 /* RLMRealm_Dynamic.h in Headers */ = {isa = PBXBuildFile; fileRef = 14E5074693C241E739C0F88EA9E26D6E /* RLMRealm_Dynamic.h */; }; + 4AC5B90C5F737677057D17D51A2581C0 /* RLMPredicateUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = A26ED6EDF207AA276CBAD6DED2156D8E /* RLMPredicateUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 4B914B45266E593F512F835750D69DE3 /* RLMAPIKeyAuth.h in Headers */ = {isa = PBXBuildFile; fileRef = F313551CDB4FD810DD3CF839F48E5598 /* RLMAPIKeyAuth.h */; }; + 4DFBC9C9B11F956CF0F14270DD1A5F10 /* RLMObject_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 156DA493B9D89EC4212074D2C995EF9C /* RLMObject_Private.h */; }; + 50443117E9BAAEE5E88AE2D202A4B79F /* RLMArray_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 8B31DC02061BD43612D97809BBE8BF74 /* RLMArray_Private.h */; }; + 5059D7DC3E94C2471AA9F96A1E91DA25 /* RLMUpdateResult.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 89578087225F22AF21C2C253BD9F15E7 /* RLMUpdateResult.h */; }; + 511C4C72919EA280FE5A26BA62C87F3A /* RLMSyncSubscription.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7B9D2B248DEA4041A5D5652F4C370372 /* RLMSyncSubscription.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 51BA9462B158C88B90D92621AB86DA45 /* RLMScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = 8665FB3F64D1560D6687B39D7E65A68F /* RLMScheduler.h */; }; + 53A11D4781B500C01BD4B7E2D3E5CD3A /* RLMManagedDictionary.mm in Sources */ = {isa = PBXBuildFile; fileRef = CEFA3AA5A6F13EF14DC0485AA3C77E26 /* RLMManagedDictionary.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 546894780B599D72BE629DE603CE1408 /* RLMObject.h in Headers */ = {isa = PBXBuildFile; fileRef = F123E905A47AB485FEE2C2B6188D39A5 /* RLMObject.h */; }; + 54A3854C13C2BC05E1F983672735E914 /* RLMSet_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CD4D935A3B6C8A82ADB9DF7455DFB90B /* RLMSet_Private.h */; }; + 56040CFFA72105E3B95C1D44A8AAD299 /* RealmSwift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 70D19506168EA3B184AB2365D7D7C50D /* RealmSwift-dummy.m */; }; + 5858E83F858272F084A4B75F0C01DFBF /* RLMSyncSubscription_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 31A8F30D8D7E0AB02362EE0AD1AF1268 /* RLMSyncSubscription_Private.h */; }; + 5859B1C3F605671841F88404BF1CBE81 /* RLMObjectBase_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = BF1DA4828D80F3F4FB062A05B6839473 /* RLMObjectBase_Private.h */; }; + 58B5581101DE8AE5EBFF2FC544D32F0C /* RLMObjectBase_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = BF1DA4828D80F3F4FB062A05B6839473 /* RLMObjectBase_Private.h */; }; + 58C96277ECC03358ED0A472DA23F3F53 /* RLMSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9164561687AF22B091FF5B25D0D938A /* RLMSupport.swift */; }; + 59D9EED2874474580D0CE585C7DC9EDC /* RLMArray_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B31DC02061BD43612D97809BBE8BF74 /* RLMArray_Private.h */; }; + 5A112F8271072DE73024CBA8078043AA /* Projection.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAEBE82E651C9E62BB79536EA987D7E9 /* Projection.swift */; }; + 5B0FE3835069F5DE3B4EE2D3C86CAB0B /* RLMResults_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 5541E31DC0879051FFC3C4EE04F765B9 /* RLMResults_Private.h */; }; + 5B6234139BBFD15C7F028858D2C591B8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 952925E838A0DE4D7BDC4EE54022633D /* Foundation.framework */; }; + 5B8A458DC7C87F427A5C463F3CAC517B /* Decimal128.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F7B3C67C23767E4B2FFBC5E3131FA8 /* Decimal128.swift */; }; + 5BF421BE48A7F2C14D62429966DF9CC3 /* RLMSchema.mm in Sources */ = {isa = PBXBuildFile; fileRef = 56900CC788B27223518F048DAECC2413 /* RLMSchema.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 5BF823878F8F6A082C28B977CBD89D0F /* RLMProviderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = A07078F84B897764F4F56E9E30C2AED9 /* RLMProviderClient.h */; }; + 5D0027837717618EAE09864D9728EB35 /* RLMEmailPasswordAuth.mm in Sources */ = {isa = PBXBuildFile; fileRef = DFABC7F89E109F6B72CC258AC4F2DB95 /* RLMEmailPasswordAuth.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 5E3DFA05C0DBBE379D00AB99AF04296E /* RLMAsyncTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D53E2B9DA57CF465830EC92CE38FEA7 /* RLMAsyncTask.h */; }; + 5EDE608C519C24AF939914110C7CE74B /* RLMLogger_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = AEF5520981A82480A9E8725B47C709F1 /* RLMLogger_Private.h */; }; + 5F0A29426B5289CE22EE51AFE0A28775 /* ObjectiveCSupport+Sync.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCB2F78A679B2F5D906564B85004679B /* ObjectiveCSupport+Sync.swift */; }; + 5F878C835ECE9613898BAADD81628269 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3B2A0B779CE31153B2C0D8A7F8DC7FE /* Security.framework */; }; + 609EB115EBE2C1BB25EE2FF2EE67A4BD /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 394000ACEC3525AB18794B5B44ECED44 /* Property.swift */; }; + 62446C4A47D2141C012B42F3CF874090 /* RLMBSON.mm in Sources */ = {isa = PBXBuildFile; fileRef = D6125B0B3BCF1040E9B3A78EB5EDF928 /* RLMBSON.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 66B68F7A52CB423990C5E3ED589FC9F9 /* RLMThreadSafeReference.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8929353C9A521D1515E318601DB0459F /* RLMThreadSafeReference.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 66BD8017F7819384898E59C08F01482F /* RLMManagedSet.mm in Sources */ = {isa = PBXBuildFile; fileRef = 44B69D33543C8F54BB506C2BDA32BCBF /* RLMManagedSet.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 67F8FAC2EA8069948CB07E41CD9A7187 /* RLMFindOneAndModifyOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 7AB66F45F8EDDFF03F80FCC411B39AAF /* RLMFindOneAndModifyOptions.h */; }; + 682649CEC1CA3CFF6F01C692754E53D5 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A80C850252DD65379ADE04815FEA92E /* App.swift */; }; + 69130970F3EA2B79379ACCAC115A7326 /* RLMFindOptions.mm in Sources */ = {isa = PBXBuildFile; fileRef = DF65E0CB75B86CAF5232510BF6C5994E /* RLMFindOptions.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 69E27BAAB5EE0731092AD1B2301D58A1 /* RLMObjectSchema.mm in Sources */ = {isa = PBXBuildFile; fileRef = 128E2A3A408DD8C462D655821E17014B /* RLMObjectSchema.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 69E7A60C8E32C5FD9D51B19C96529484 /* RLMResults.h in Headers */ = {isa = PBXBuildFile; fileRef = E3F27588B6819F964CCE16A4A87A0B84 /* RLMResults.h */; }; + 6AB49426FB6ADB70AE672224937E64A9 /* RLMLogger.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 97ACC83057F43D9B6980F6F7C750B9DF /* RLMLogger.h */; }; + 6B417758244574B7B3C30ACED4931D87 /* RLMResults.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98E948B5C4D15AEC19AA92F80B2AFC28 /* RLMResults.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 6BB65F955B515386823B4E2489460EC2 /* RLMScheduler.mm in Sources */ = {isa = PBXBuildFile; fileRef = D31E3586B5A91CF716C4428503A3CFCD /* RLMScheduler.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 6C30B5428653570B67A240D491AA0B2C /* RLMRealm_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E1819A1DE7516208F40BA9103184CB9 /* RLMRealm_Private.h */; }; + 6C49271A9472DCAA4D047D65D9B0FEC2 /* RLMUserAPIKey.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D9C769A591C3C701C4B3D66805689FD /* RLMUserAPIKey.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 6C523F77EC93669F5110AD340DD7FA4C /* RLMRealmConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = A418A33CBA33C7CA3777D174F9A7F6E3 /* RLMRealmConfiguration.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 6CCE4E2180DE5FEB5B8CE98B9768DE6D /* RLMFindOneAndModifyOptions.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 7AB66F45F8EDDFF03F80FCC411B39AAF /* RLMFindOneAndModifyOptions.h */; }; + 6CF869385B68714ECCF7C24A53EBCCF2 /* RLMError.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = DC906F177DFF762E0F2E2A4095889CFE /* RLMError.h */; }; + 6D311C71E3835300ED0B39A347395894 /* RLMProperty.mm in Sources */ = {isa = PBXBuildFile; fileRef = 43C6952CC7740B9F3AFD6D7C5FBB1472 /* RLMProperty.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 6EEF08E1970531934EA69185040B71F1 /* RLMCredentials.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 8D260A52C53254A6FF21693A13B6D241 /* RLMCredentials.h */; }; + 6F0BD1ED488665BCB5E418BFB949379B /* RLMSchema.h in Headers */ = {isa = PBXBuildFile; fileRef = 44BE1AE28CD9E51D7A284CB0F4570743 /* RLMSchema.h */; }; + 6FC16F5639926D99A63C51C6AB855C2D /* PropertyAccessors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A3950C70D95063F4AA9D6404705A82 /* PropertyAccessors.swift */; }; + 7003751838B815A2CED970B9FFE2E472 /* RLMApp.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 170BFD8D6212C2BE4613E8915FE93911 /* RLMApp.h */; }; + 70B38FE38BC1033664F4287CCC545BB3 /* RLMApp_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 2F6C9E50FB69103202B6E5F4AD647AAB /* RLMApp_Private.h */; }; + 7190FAB0A2288A73BB2C10D69492068D /* RLMFindOneAndModifyOptions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 58E58D6C4EE9BB5E393E64A3A8B042B0 /* RLMFindOneAndModifyOptions.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 71ED8B725658B0D3E35D4B72106BC615 /* SchemaDiscovery.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF36B120935792B4001A5634115A5AE9 /* SchemaDiscovery.swift */; }; + 72C4A427880F50CD06F2246543F5A63E /* RLMObjectBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 1AF58B2A8E5F1848F36BD2D6637AC585 /* RLMObjectBase.h */; }; + 72F625D1872BACF2B714F35BD4400C16 /* RLMMongoCollection_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 20F8BD3214B20EF37E8F662ACCAAA60C /* RLMMongoCollection_Private.h */; }; + 732981CA8A49AA1C8CAA06E28CB5009F /* RLMUserAPIKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 8503B74C1678228FF9FC0BA42CE15096 /* RLMUserAPIKey.h */; }; + 7454B210CB9C12F734E6CF5781D77750 /* RLMCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4DDAFDDCA2217B2266A2A7953A11B8C8 /* RLMCollection.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 752C7184ED4531729174293BFC7AF6E7 /* Migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBA363FD1B97BB56E61F71F2AF92764B /* Migration.swift */; }; + 76623954A536129B13F2FFCEE433284C /* RLMDictionary_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72CC1F1C755FBC3CF1BAA38D53EE2BE1 /* RLMDictionary_Private.h */; }; + 7686BDEA02FB018135B77E758C91C1EB /* RLMMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = F0CA69915FC0A9DE4556DCAC4009F263 /* RLMMigration.h */; }; + 76D6A67C276309C675005F8F2D9BACD5 /* RLMCollection_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 3EE21D373515813C8D8187A7DB408B8F /* RLMCollection_Private.h */; }; + 781671C9525101E2C5AC80A6C3DF54C6 /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDAF7E43CDAEE6A562D7DE73E48BBD34 /* Map.swift */; }; + 79DF5164542097A87970D857C22688FD /* SectionedResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CD3E27F8461649EAEFA0D4C6F00E51 /* SectionedResults.swift */; }; + 7AA5D2ED28C6B278DB39BC615D38ED5B /* EmbeddedObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799DEF74847E011F991ED851F8FB9AD5 /* EmbeddedObject.swift */; }; + 7BA7FEA98B6EF202744404FD8199BC91 /* RLMPushClient.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 68B7ABFB3FB23D05DCFCBD5E4F60D8C1 /* RLMPushClient.h */; }; + 802C8700DC0809CF4002A2CFA2BED876 /* RLMThreadSafeReference.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 28BDE71E985AC8FBF505AD02C4B30C06 /* RLMThreadSafeReference.h */; }; + 8149453866F74E14E251C543C00F4F4A /* RLMRealm+Sync.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 8BF652086B82FCB285AF95A331F06874 /* RLMRealm+Sync.h */; }; + 820BF0662635667610DD218CFAC68030 /* RLMUUID.mm in Sources */ = {isa = PBXBuildFile; fileRef = D43F5F1C05A626BF68E6115C5309DE07 /* RLMUUID.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8276813797DCDB61494C190FC4E19060 /* RLMAPIKeyAuth.mm in Sources */ = {isa = PBXBuildFile; fileRef = 12E0802B8D1CD4C7F7B06EB8B6161352 /* RLMAPIKeyAuth.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8319F4D6CA27AB8D6DB919DDEF0168FC /* RLMMigration.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = F0CA69915FC0A9DE4556DCAC4009F263 /* RLMMigration.h */; }; + 83E05D94926C7E9E091B3C409A8C4892 /* RLMSwiftValueStorage.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 97803D1FC1CC8551BE103980CD22B5E9 /* RLMSwiftValueStorage.h */; }; + 840529400322C792BCEBF26F90723CA4 /* RLMAccessor.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBAAA7D9AF1F57EA8E05B3BB9ED1F8D /* RLMAccessor.h */; }; + 856241060FCD8F54D41C8100D5467EA1 /* RLMError.mm in Sources */ = {isa = PBXBuildFile; fileRef = 50C117353A5193CCEC27DB1764BCCEE3 /* RLMError.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 86398C0FDA78F714415C4D95A995C250 /* RLMObjectBase.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 1AF58B2A8E5F1848F36BD2D6637AC585 /* RLMObjectBase.h */; }; + 868EC2D6F5E462D6EC55BCAA99DA1848 /* ObjectiveCSupport+BSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3A44DB03BC89613444A8677AF8B9718 /* ObjectiveCSupport+BSON.swift */; }; + 876EE37947934409808939990FBC28D7 /* SwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = F15C0DD85D5AB5EE382380DB7D379A41 /* SwiftUI.swift */; }; + 87A5DD69BBFC72B10DCE234AD915AECA /* RLMEmbeddedObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = C6CDC4F0BC0FEF0BF1EDAFBE780C3FC0 /* RLMEmbeddedObject.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8A3E3F36EEEE830D273FB455144921CF /* RLMRealmUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A7E1E1F583157E97280C2C11F60253D /* RLMRealmUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8A9025AE4A9232EF04AAFFA2EEA1416F /* ComplexTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EC5EE6912182E015407E574294ABDCC /* ComplexTypes.swift */; }; + 8B2072B251574B461AEF7A915C8AF90F /* RLMObject_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 156DA493B9D89EC4212074D2C995EF9C /* RLMObject_Private.h */; }; + 8BD86B5E5C4D9040FF6F940A7DDE5B5E /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = A00386484AF93B1D69A5F465564FF33F /* Events.swift */; }; + 8BD9D141C5B7707226B40ED458DE9A46 /* RLMCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FEC31B25442C280C915CF78B83081E /* RLMCollection.h */; }; + 8BFA582E32D4CCA22809D5D430075BA1 /* RLMUser_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 931FFD633662A9674B8F3EF39579EB5C /* RLMUser_Private.h */; }; + 8C42A7A9022BBAFCF982F250E3A7500D /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE9917146111B7CF81BE6A9EA9097B7 /* Schema.swift */; }; + 8E4946AF47D0CB535546BCCC8EFA5ED3 /* RLMPushClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = 23D58A0A4DF4703C125A90D1398E776E /* RLMPushClient.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8F3B61FDAC0D3D8226AADDF013946108 /* RLMMongoDatabase.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 86C82009901EC92F1F93D8D4E50B2632 /* RLMMongoDatabase.h */; }; + 8F43278BE5C756108EA3A0B50803EC0F /* RLMObjectId.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = E003BD497C568C08EC768CD231F1AD26 /* RLMObjectId.h */; }; + 8F82E78D6E8BB8CFF319D8D1F5BC7204 /* RLMValue.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 656A2602114C6F39008996487E53F025 /* RLMValue.h */; }; + 8FE84C22C10FB60A6415744AB2F868A1 /* RLMSyncConfiguration.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = A9C89270B39D91E8A818E34F32C7799A /* RLMSyncConfiguration.h */; }; + 910145FF03824ABFF17CA653C7F0BD5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 952925E838A0DE4D7BDC4EE54022633D /* Foundation.framework */; }; + 91420C785F4816950347FCF77F2179E3 /* RLMSyncSubscription.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 68D58FC196381235BC49DEF871BC6C4E /* RLMSyncSubscription.h */; }; + 91A36FDEDB3697B2A9CF64A4C1517106 /* RLMCredentials.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D260A52C53254A6FF21693A13B6D241 /* RLMCredentials.h */; }; + 92C86DD35BB35AD8C829F7BD677E1BD5 /* RLMSchema_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72BBEB735A09A89265B342D9D00DD130 /* RLMSchema_Private.h */; }; + 940BA64E3D53B7F4E75B9A154B10AE96 /* RLMUserAPIKey.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 8503B74C1678228FF9FC0BA42CE15096 /* RLMUserAPIKey.h */; }; + 958A22AD0045E6D0159B7D4BB3EC46DB /* RLMAsyncTask.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7BD82FB62C4C6F66BB1E560622D260E1 /* RLMAsyncTask.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 971328B5C2BBA4D11D1EDA68799FCBD6 /* RLMRealm.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 3A122237AC82FC67FCCBBC7B49CF3B6F /* RLMRealm.h */; }; + 97BF699AC80B0A8F6D3A89EBE06C699E /* RLMObjectId.mm in Sources */ = {isa = PBXBuildFile; fileRef = F1B535C48AA27A28600CB292BA7B62C1 /* RLMObjectId.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 97FC352B1ECE6980A313E50222CA100C /* RLMAPIKeyAuth.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = F313551CDB4FD810DD3CF839F48E5598 /* RLMAPIKeyAuth.h */; }; + 9811B1C4F898EB3970895029EDFD7436 /* RLMSwiftObject.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 251F62CD7F86A4BDC5A5251E2EC9CDE5 /* RLMSwiftObject.h */; }; + 9967BBD9E33F5310CEA67C1F1ABBF273 /* RLMDecimal128.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = E5D51CF7CC72E3E01269B1108CD73D9A /* RLMDecimal128.h */; }; + 99FFBD71C9DDFBB0A14EFDA97F1B02B7 /* Pods-Bremer-BremerUITests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = CF24E6101AE36BCE037294AB302C146B /* Pods-Bremer-BremerUITests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9C20856EDF5A9D048A25A0E5E6C4D6EC /* RLMSet_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = CD4D935A3B6C8A82ADB9DF7455DFB90B /* RLMSet_Private.h */; }; + 9C38F4A2700C7A8FA3E01DF077CD7B6D /* RLMUpdateResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 89578087225F22AF21C2C253BD9F15E7 /* RLMUpdateResult.h */; }; + 9C7A9DE5E81599EB456F1D454F9B9360 /* NSError+RLMSync.h in Headers */ = {isa = PBXBuildFile; fileRef = 5AF7E94666A9B45384AB13E181E4CD57 /* NSError+RLMSync.h */; }; + 9D088891C4077B7C96B4626A7C9C0113 /* RLMSwiftProperty.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 98A99A950E295F01B3CE7F2FBBEBC429 /* RLMSwiftProperty.h */; }; + 9D1C7542A7BCDEBA0F62F273FD7231B0 /* Realm-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E96A87D4C9F5DE31C5D4A08F2B80B71 /* Realm-dummy.m */; }; + A0E1E99D275AC0763FDC74D83CB671A1 /* RLMArray.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = F6C1A5EFD84B6A50454D576EA03B4DB4 /* RLMArray.h */; }; + A2D241953E4F2DA88EEC3CED7DEDF8B1 /* Realm.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C44617F54A134E586D8A6138AEBF85 /* Realm.swift */; }; + A30CECDE48E690E4C81DFAACB9D48A3C /* RLMQueryUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = 202E9650F11F6AD66598EC94505C0DC0 /* RLMQueryUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + A34746857C1D93ED5EB769679BE3348B /* RLMSwiftValueStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 97803D1FC1CC8551BE103980CD22B5E9 /* RLMSwiftValueStorage.h */; }; + A6E6072DF7430D90EA6DC3066FA7F7C7 /* RLMFindOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = E2902657D4B3DF4F908B849A1F5FFD8F /* RLMFindOptions.h */; }; + A90CBD8E1781E2E19989DD93E5BE8033 /* RLMSyncConfiguration_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 31ADBCF4BF2601BDCF3BEB00B234A65A /* RLMSyncConfiguration_Private.h */; }; + A961A6A4F5DEEEEFD5A03DF58AD26462 /* RLMSyncManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 0AF05C6D9B63DCA0A6436D62E942292E /* RLMSyncManager.h */; }; + A9AE14432BFCB62033691DD12204CC5A /* RLMApp.mm in Sources */ = {isa = PBXBuildFile; fileRef = 590D63CB0677446E02281D23D4692E4C /* RLMApp.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + A9CCD04E513E9AF636B6D2836A51BAEF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 952925E838A0DE4D7BDC4EE54022633D /* Foundation.framework */; }; + AAD9FDCF7389C0EFE67CCD5B9BAF3115 /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CCBCA3A7CCA35C254E7412CD7B5C33B /* Optional.swift */; }; + AB60957A130323D5FACF4F2991B70391 /* RLMRealm+Sync.mm in Sources */ = {isa = PBXBuildFile; fileRef = C2FC7E591096B5B21551F74E7DE51CDD /* RLMRealm+Sync.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + ABD61BF538B0440B014502E121AD906D /* MongoClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79B0FE938D2F799ECCA6EDFA678A1B91 /* MongoClient.swift */; }; + AC2B3358725F8AFB36A2CD27240177F2 /* RLMRealm_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 4E1819A1DE7516208F40BA9103184CB9 /* RLMRealm_Private.h */; }; + AFFEB160C9DAC32478B61FCCED14535B /* PersistedProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DD5C52ED1637C35CFF24F78FA8E7F34 /* PersistedProperty.swift */; }; + B040048B02022042FAD7AA495FCB0323 /* RLMRealmConfiguration_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 99AA99D23861CC51BB876FA7CDEAE774 /* RLMRealmConfiguration_Private.h */; }; + B0F6648B7B06016F49CFAE0A6D837DF4 /* RLMNetworkTransport.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = DD6CF5C22D43D0340212EFD3A0341BE7 /* RLMNetworkTransport.h */; }; + B227477A74825C9A83083C0433CBFDD8 /* RLMAsymmetricObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 748B44A932F1CC48BB670ED0D3ACC753 /* RLMAsymmetricObject.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + B2A59ED57987B4C045C2E426CA784F3C /* RLMNetworkTransport.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1D7A1F605D5891D44CC5D45CB5309EC8 /* RLMNetworkTransport.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + B46E52EDBD14DEA140A5EE7F128F7D70 /* RealmProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF39689A0A6790771DC1773757C1EAF /* RealmProperty.swift */; }; + B4EE276AF7CB12ED9DB48318D8914C2B /* RealmCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B57CFF0C89A929D0188B77FF91CB915 /* RealmCollection.swift */; }; + B59E22971F8D4CE5681BF67535A363F7 /* Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B7374F60D29EB95FE8F0B6E7BC6981C /* Combine.swift */; }; + B6051B422B346D7C2C0C78083AE42593 /* RLMCollection_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 3EE21D373515813C8D8187A7DB408B8F /* RLMCollection_Private.h */; }; + B785E35AE212C2CB4C4CD0D84C49B90D /* AsymmetricObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BCF4F4DFBF323D1F496E7AA905F6829 /* AsymmetricObject.swift */; }; + B837F9BAA1E321E18780F3B8903BC004 /* MutableSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F9EF2D06DD5F0C3364A50CFFD27175 /* MutableSet.swift */; }; + B9B88E7ED730F1F89746B2448FE19D6D /* RLMThreadSafeReference.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BDE71E985AC8FBF505AD02C4B30C06 /* RLMThreadSafeReference.h */; }; + BAD6F720447F880C4E8C293236558AA2 /* RLMEvent.mm in Sources */ = {isa = PBXBuildFile; fileRef = DD5F9555DB50862C43611118F9E6FF20 /* RLMEvent.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + BBCE391F1AC55EFC2A589E550ACCC1B6 /* ObjectiveCSupport+AnyRealmValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B4DD113336EDCBA8E57663DAC98DAED /* ObjectiveCSupport+AnyRealmValue.swift */; }; + BC3767360C4E6C8373B927EEEFF2310D /* RLMSwiftSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EB3A9E52A23FB3F9B23BBF63DD7653A /* RLMSwiftSupport.m */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + BCC16BD326E2270E91F40163F6E39DA1 /* RLMRealmConfiguration_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 99AA99D23861CC51BB876FA7CDEAE774 /* RLMRealmConfiguration_Private.h */; }; + BEBEEBDD6543109E845B69CC102EF872 /* RLMDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 308DBDE082D41F22F50C92F0219C0282 /* RLMDictionary.h */; }; + BF5352E6A21E27DB879C2189155F17EA /* BasicTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC2DDB1B7EB185FFE2B8E387885B7842 /* BasicTypes.swift */; }; + C11339074CE5C4A8DF75384CCC987B77 /* ObjectId.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED205C636A7332EDE1203A29F356F902 /* ObjectId.swift */; }; + C1FD432E9CBF46B53AEB2152A00DCC91 /* RLMMongoCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 7382B395581C4D5173DD3D9F1FA73E6E /* RLMMongoCollection.h */; }; + C227A035FABE8C27079FB27231960CA2 /* RLMSyncSession.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 3C6F253DE442B7CD2596F4212103F666 /* RLMSyncSession.h */; }; + C34D354EFB0278C45DFBF4DA47DEBF74 /* RLMSectionedResults.mm in Sources */ = {isa = PBXBuildFile; fileRef = C0040FBF8247CDC8C0A0291B31DB2C6E /* RLMSectionedResults.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + C49A30D54C6C024842C726A7A0A349C3 /* RLMConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 7EBA5CFE49DBE74E402A458118E45875 /* RLMConstants.m */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + C50B84D7B7EEB94A97C13C8AD3F7E23D /* Pods-Bremer-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7002EA128EE9AD22020152C5C6894C5F /* Pods-Bremer-dummy.m */; }; + C57AA7AA381473F8C9FEE4FD7179E6B3 /* RLMDictionary.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 308DBDE082D41F22F50C92F0219C0282 /* RLMDictionary.h */; }; + C97E9141FEDD6F16EE8EB2FD7D84CA3F /* RLMMongoClient.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = A6954DA60DEE09E47284DFB14176FC5C /* RLMMongoClient.h */; }; + CBFF08499AB31E38171D297AF970C55C /* RLMClassInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0EC784486BA2B84E7CC5BF4FFE73B033 /* RLMClassInfo.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + CBFF56BD941E3BAE6D8A1A7CCBB4F207 /* RLMSet.mm in Sources */ = {isa = PBXBuildFile; fileRef = 328DA24E2F0FFF97F378C482A57756A6 /* RLMSet.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + CCC55B25CFC9567D6A2803336B7D1D17 /* RLMDecimal128.h in Headers */ = {isa = PBXBuildFile; fileRef = E5D51CF7CC72E3E01269B1108CD73D9A /* RLMDecimal128.h */; }; + CCD1C585CE4E9DBE15769F38E06842C2 /* ThreadSafeReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67092FC5F8649E5A26AE847AD8A8876D /* ThreadSafeReference.swift */; }; + D0A22FECD9AFFEC60B35A58BEE37A51A /* RLMNetworkTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = DD6CF5C22D43D0340212EFD3A0341BE7 /* RLMNetworkTransport.h */; }; + D1243934E772496997298DBFF0DE3422 /* RLMProperty_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 6925048E7FF653A3F7FDA6C80603546F /* RLMProperty_Private.h */; }; + D15B7847ABF90E0B55C6EF7C8EDF3158 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 952925E838A0DE4D7BDC4EE54022633D /* Foundation.framework */; }; + D40B4ABC458054D8C3E5D10377A2CEE0 /* RLMSyncUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAC151E989BE61BE27894E9466897C9D /* RLMSyncUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + D504D18B65C4071A08171C05D5B592D1 /* RLMResults_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 5541E31DC0879051FFC3C4EE04F765B9 /* RLMResults_Private.h */; }; + D557744183CF5535DECED314499DDE07 /* RLMMongoCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 36DA7DE9E336E47CEB58E15845B6188C /* RLMMongoCollection.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + D6725A83F0BDF7F1CD1EFD5DB116CE0A /* RLMDictionary.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98406ED6D7929CB5C414D49E3028B995 /* RLMDictionary.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + D82B59171BB4C4C7158759A41E6FECF6 /* RLMRealm.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CF79020CE57ECA510B1E580B1CE98E5 /* RLMRealm.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + D9139F2BD1B5CDA5378FE801681A67AB /* RLMObjectSchema_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 757457E7DEA8C2AA02BAF76C46377329 /* RLMObjectSchema_Private.h */; }; + D9A7B2A7821605D50409B738534A23F6 /* Realm.h in Headers */ = {isa = PBXBuildFile; fileRef = FE8350F6C1FADE55F9BF782D08FDABFD /* Realm.h */; }; + D9D541537E0E9CBE619FCB4C5BA41FBC /* Pods-BremerTests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 54929AAB01C9B10B946F41FBDF583DF4 /* Pods-BremerTests-dummy.m */; }; + D9D8EA266CD7C5885464952BC9B2678D /* ObjcBridgeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E57599782133BDF9EB8C7DFCEC56D992 /* ObjcBridgeable.swift */; }; + DC1CC94EA95338783CD4596CF2882942 /* List.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB2B37C3887EC2A789C5465BD724856A /* List.swift */; }; + DC846F05C78BFE7388A9FCC22D6855C0 /* RLMDecimal128.mm in Sources */ = {isa = PBXBuildFile; fileRef = B2B3CF7C7D1F83C09082DF1C6AFB0159 /* RLMDecimal128.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + DD5565CB03976C136614929A24AFEB00 /* RLMLogger.mm in Sources */ = {isa = PBXBuildFile; fileRef = 017195EB54DBECB50C413EB1A820E94D /* RLMLogger.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + DE9AC4D1B35C9E07B979930D5C0B38DF /* CollectionAccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92DC24CEF1BFE8D67401AA89AE318EAB /* CollectionAccess.swift */; }; + DEB4B1192A01C11306500422A677D67D /* RLMSectionedResults.h in Headers */ = {isa = PBXBuildFile; fileRef = D33AC4A4F700EB53303DA72A42DADD96 /* RLMSectionedResults.h */; }; + DFE3D9A4694A51FD0214E86873DA558A /* RLMObjectSchema_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 757457E7DEA8C2AA02BAF76C46377329 /* RLMObjectSchema_Private.h */; }; + E10CC1254774629FBF9FE84379F3AE1F /* RLMAccessor.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCF15A7FAB1BAB6CF87FA1E1240EAA22 /* RLMAccessor.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + E29E3E106023F452D942798B1A98C791 /* RLMAccessor.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = AFBAAA7D9AF1F57EA8E05B3BB9ED1F8D /* RLMAccessor.h */; }; + E34B80A9A8B49857FCD043CAE44D1EC0 /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A6961C92C6C022D5E9CC07787774CC /* Util.swift */; }; + E366E515D6BD30A71F323FE37BCC1A28 /* Pods-BremerTests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 084EDB73408D5ED54E37CC7A8193791C /* Pods-BremerTests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E3DC7B809D4812814D1275565D9A52B7 /* RLMRealm.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A122237AC82FC67FCCBBC7B49CF3B6F /* RLMRealm.h */; }; + E6595B00A83513B21DC169C6319F834F /* RLMSyncSubscription_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 31A8F30D8D7E0AB02362EE0AD1AF1268 /* RLMSyncSubscription_Private.h */; }; + E67507D98B3AFB1C33E80C4999086D23 /* RLMProviderClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFB0657BB0ABFDBE61C1E243296B0A /* RLMProviderClient.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + E7E8EB6C98BEBF86A61A10162B9D53DB /* RLMObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 438EEDFCDE953A0FB47AF574D22EB312 /* RLMObject.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + E7FE0FE9CCC81F971080577E75A9BADF /* RLMCredentials.mm in Sources */ = {isa = PBXBuildFile; fileRef = 966AE395BC3B71F90831AFE79586D893 /* RLMCredentials.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + E899987F3E6214F43909608AE045620A /* RLMPushClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B7ABFB3FB23D05DCFCBD5E4F60D8C1 /* RLMPushClient.h */; }; + E8E68A15275FD6942B3345A9CD29D237 /* RLMUser_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 931FFD633662A9674B8F3EF39579EB5C /* RLMUser_Private.h */; }; + EECB495C6174780DAD8256BE67151B97 /* RLMFindOptions.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = E2902657D4B3DF4F908B849A1F5FFD8F /* RLMFindOptions.h */; }; + F0C6422CF158E3038EF195C6B04B3597 /* RLMArray.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3E07A833E0493B8D3F6A88C794F249EA /* RLMArray.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + F0C68CAD88EEDA948E59BB2E89EC3052 /* RLMApp_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F6C9E50FB69103202B6E5F4AD647AAB /* RLMApp_Private.h */; }; + F3117B7CBCA74424D090B0911C96DC89 /* Object.swift in Sources */ = {isa = PBXBuildFile; fileRef = B275916C09492961BE9FF64C026D7D5B /* Object.swift */; }; + F48B3E0D431BBBC6904CDCD2CF90031B /* RLMSet.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = BA42A0E2BDA802CD41C5791B01D95C8A /* RLMSet.h */; }; + F48BBB342D22A1EE7AC2508682F827AE /* RLMSyncConfiguration_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 31ADBCF4BF2601BDCF3BEB00B234A65A /* RLMSyncConfiguration_Private.h */; }; + F80CCCEBF9794DC3E8B4EEB8FAAA2D0B /* ObjectSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B3CD4A2BD648DA78AC6D18274B7B3BE /* ObjectSchema.swift */; }; + F94371C9169BE3AE599827232C38D2B0 /* RLMEmbeddedObject.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 1093D1C3E0121F776B90F3F425A05747 /* RLMEmbeddedObject.h */; }; + F9FA019AA5F4715F439D87602AA6E16E /* RLMRealmConfiguration.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 5048457FAC7400CC15E9FF5E34CC736B /* RLMRealmConfiguration.h */; }; + FCA3AA572DB59FC9E2E45FEB3100DAF5 /* RLMConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 407AB4F6922BDF4346E500A6611B2925 /* RLMConstants.h */; }; + FE2F13D80F1F4B8A605390C3399EF3AD /* RealmKeyedCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5AEF06E9131F34D02F83FB90CE4793B /* RealmKeyedCollection.swift */; }; + FE37B576B68AC2671F9ADCB2FDC555C6 /* RLMObjectBase_Dynamic.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6AE9474A96853A8CCEB7217E7882B1 /* RLMObjectBase_Dynamic.h */; }; + FE7FC652161CB9CBDDBA9E5BE3397011 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F7EFF56DEE55B0043740912E928BE2B /* Error.swift */; }; + FF21C29F2325E747CC04BA19B21CF38F /* RLMSwiftObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 251F62CD7F86A4BDC5A5251E2EC9CDE5 /* RLMSwiftObject.h */; }; + FFC5AD5D9C84E7800EB949BFC5E51EE0 /* RLMUpdateChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = C0004D5E5EFD0B9DB132A9665F5722ED /* RLMUpdateChecker.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.42.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 6E62B7B55E80A98A7C3B305B2D5767E5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9399214D42B91BBCB8EFD6308884653C; + remoteInfo = "Pods-Bremer"; + }; + A294B51E81F4F9714F641F956BCDFDD4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 68494F30B4A13F8E5E88BCCAEC25B0A4; + remoteInfo = Realm; + }; + AA0E21EBF22F66387EFA4044F9352A74 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 68494F30B4A13F8E5E88BCCAEC25B0A4; + remoteInfo = Realm; + }; + CB828421E54C4F9E9403280D1039F501 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 782725687624F8665247B84AB581BEB1; + remoteInfo = RealmSwift; + }; + D6A4888DF0287DD834BE6DAF07C350C7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 782725687624F8665247B84AB581BEB1; + remoteInfo = RealmSwift; + }; + FC2F95BCBA2B20A264CB04B37382F5B9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 68494F30B4A13F8E5E88BCCAEC25B0A4; + remoteInfo = Realm; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 19CAE12F0E356F370555E49572DB2EF2 /* Copy . Public Headers */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(PUBLIC_HEADERS_FOLDER_PATH)/."; + dstSubfolderSpec = 16; + files = ( + 25288A0E049B582F8B97030FC89F2188 /* NSError+RLMSync.h in Copy . Public Headers */, + 1264261A2DE5E83DFAC6D96FDE9A17D9 /* Realm.h in Copy . Public Headers */, + 97FC352B1ECE6980A313E50222CA100C /* RLMAPIKeyAuth.h in Copy . Public Headers */, + 7003751838B815A2CED970B9FFE2E472 /* RLMApp.h in Copy . Public Headers */, + A0E1E99D275AC0763FDC74D83CB671A1 /* RLMArray.h in Copy . Public Headers */, + 0E7A97BD7EA7026B0879CAAD82C7BC9A /* RLMAsymmetricObject.h in Copy . Public Headers */, + 163BE3484DDE34A40D0A16522F394367 /* RLMAsyncTask.h in Copy . Public Headers */, + 2B1A964A2AF4B39439A8C7B7E3DF1811 /* RLMBSON.h in Copy . Public Headers */, + 1C48FF8C98F113D2885F9AC5DC711058 /* RLMCollection.h in Copy . Public Headers */, + 409221ABB1CE39C1A87EE5E10B03225E /* RLMConstants.h in Copy . Public Headers */, + 6EEF08E1970531934EA69185040B71F1 /* RLMCredentials.h in Copy . Public Headers */, + 9967BBD9E33F5310CEA67C1F1ABBF273 /* RLMDecimal128.h in Copy . Public Headers */, + C57AA7AA381473F8C9FEE4FD7179E6B3 /* RLMDictionary.h in Copy . Public Headers */, + 30E832A6E54FCBA6BCC6CB16671A697D /* RLMEmailPasswordAuth.h in Copy . Public Headers */, + F94371C9169BE3AE599827232C38D2B0 /* RLMEmbeddedObject.h in Copy . Public Headers */, + 6CF869385B68714ECCF7C24A53EBCCF2 /* RLMError.h in Copy . Public Headers */, + 6CCE4E2180DE5FEB5B8CE98B9768DE6D /* RLMFindOneAndModifyOptions.h in Copy . Public Headers */, + EECB495C6174780DAD8256BE67151B97 /* RLMFindOptions.h in Copy . Public Headers */, + 6AB49426FB6ADB70AE672224937E64A9 /* RLMLogger.h in Copy . Public Headers */, + 8319F4D6CA27AB8D6DB919DDEF0168FC /* RLMMigration.h in Copy . Public Headers */, + C97E9141FEDD6F16EE8EB2FD7D84CA3F /* RLMMongoClient.h in Copy . Public Headers */, + 3C6886B7C7A89AFEA13AE77D9B52F529 /* RLMMongoCollection.h in Copy . Public Headers */, + 8F3B61FDAC0D3D8226AADDF013946108 /* RLMMongoDatabase.h in Copy . Public Headers */, + B0F6648B7B06016F49CFAE0A6D837DF4 /* RLMNetworkTransport.h in Copy . Public Headers */, + 43CD2267C95A4B1EBFE60AD7B3F8E485 /* RLMObject.h in Copy . Public Headers */, + 86398C0FDA78F714415C4D95A995C250 /* RLMObjectBase.h in Copy . Public Headers */, + 0EDF63B3A2C61F94E8716B73FABA19C2 /* RLMObjectBase_Dynamic.h in Copy . Public Headers */, + 8F43278BE5C756108EA3A0B50803EC0F /* RLMObjectId.h in Copy . Public Headers */, + 00D2EA50D76FE77C68B05C6174F0E50D /* RLMObjectSchema.h in Copy . Public Headers */, + 25F3F292FF644A128DA6ED70F562BFE6 /* RLMProperty.h in Copy . Public Headers */, + 1F59E2EDE8BB7806133ED73D31F1CAE7 /* RLMProviderClient.h in Copy . Public Headers */, + 7BA7FEA98B6EF202744404FD8199BC91 /* RLMPushClient.h in Copy . Public Headers */, + 971328B5C2BBA4D11D1EDA68799FCBD6 /* RLMRealm.h in Copy . Public Headers */, + 8149453866F74E14E251C543C00F4F4A /* RLMRealm+Sync.h in Copy . Public Headers */, + 1BD4BFDCB4734F61ECEFD90BBD45BE97 /* RLMRealm_Dynamic.h in Copy . Public Headers */, + F9FA019AA5F4715F439D87602AA6E16E /* RLMRealmConfiguration.h in Copy . Public Headers */, + 42606A9EC6B47ACFFCD3795165998394 /* RLMResults.h in Copy . Public Headers */, + 298946030A825D7750016DCAFEE23039 /* RLMSchema.h in Copy . Public Headers */, + 29C7AB9EE67DB83850C75692523842D4 /* RLMSectionedResults.h in Copy . Public Headers */, + F48B3E0D431BBBC6904CDCD2CF90031B /* RLMSet.h in Copy . Public Headers */, + 33E19DC5B0C4219F9DBA3DA065C3D2D5 /* RLMSwiftCollectionBase.h in Copy . Public Headers */, + 9811B1C4F898EB3970895029EDFD7436 /* RLMSwiftObject.h in Copy . Public Headers */, + 83E05D94926C7E9E091B3C409A8C4892 /* RLMSwiftValueStorage.h in Copy . Public Headers */, + 8FE84C22C10FB60A6415744AB2F868A1 /* RLMSyncConfiguration.h in Copy . Public Headers */, + 2EF91AF0889342D1B81D1DEA288D7415 /* RLMSyncManager.h in Copy . Public Headers */, + C227A035FABE8C27079FB27231960CA2 /* RLMSyncSession.h in Copy . Public Headers */, + 91420C785F4816950347FCF77F2179E3 /* RLMSyncSubscription.h in Copy . Public Headers */, + 802C8700DC0809CF4002A2CFA2BED876 /* RLMThreadSafeReference.h in Copy . Public Headers */, + 5059D7DC3E94C2471AA9F96A1E91DA25 /* RLMUpdateResult.h in Copy . Public Headers */, + 0D6C52E690487D298703BC1EAA63C0B3 /* RLMUser.h in Copy . Public Headers */, + 940BA64E3D53B7F4E75B9A154B10AE96 /* RLMUserAPIKey.h in Copy . Public Headers */, + 8F82E78D6E8BB8CFF319D8D1F5BC7204 /* RLMValue.h in Copy . Public Headers */, + ); + name = "Copy . Public Headers"; + runOnlyForDeploymentPostprocessing = 0; + }; + 542F1A369041BB7B845B320F71D685F4 /* Copy . Private Headers */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(PRIVATE_HEADERS_FOLDER_PATH)/."; + dstSubfolderSpec = 16; + files = ( + E29E3E106023F452D942798B1A98C791 /* RLMAccessor.h in Copy . Private Headers */, + 70B38FE38BC1033664F4287CCC545BB3 /* RLMApp_Private.h in Copy . Private Headers */, + 50443117E9BAAEE5E88AE2D202A4B79F /* RLMArray_Private.h in Copy . Private Headers */, + 117A753CAB61836303AD4FAE1513D581 /* RLMAsyncTask_Private.h in Copy . Private Headers */, + 76D6A67C276309C675005F8F2D9BACD5 /* RLMCollection_Private.h in Copy . Private Headers */, + 0F66BB0F0515C22CF07887AD73317FC7 /* RLMDictionary_Private.h in Copy . Private Headers */, + 2670A5A2789DA3553D275F63297A52F1 /* RLMEvent.h in Copy . Private Headers */, + 39901C4D4268B4A4DCEFFEAAAF86F485 /* RLMLogger_Private.h in Copy . Private Headers */, + 72F625D1872BACF2B714F35BD4400C16 /* RLMMongoCollection_Private.h in Copy . Private Headers */, + 4DFBC9C9B11F956CF0F14270DD1A5F10 /* RLMObject_Private.h in Copy . Private Headers */, + 5859B1C3F605671841F88404BF1CBE81 /* RLMObjectBase_Private.h in Copy . Private Headers */, + D9139F2BD1B5CDA5378FE801681A67AB /* RLMObjectSchema_Private.h in Copy . Private Headers */, + 127D768C00E02D0644E825FED6D4A8AD /* RLMObjectStore.h in Copy . Private Headers */, + D1243934E772496997298DBFF0DE3422 /* RLMProperty_Private.h in Copy . Private Headers */, + AC2B3358725F8AFB36A2CD27240177F2 /* RLMRealm_Private.h in Copy . Private Headers */, + B040048B02022042FAD7AA495FCB0323 /* RLMRealmConfiguration_Private.h in Copy . Private Headers */, + D504D18B65C4071A08171C05D5B592D1 /* RLMResults_Private.h in Copy . Private Headers */, + 434FB2F0E1D2A41F940B3FBFF8B4E816 /* RLMScheduler.h in Copy . Private Headers */, + 32C6E8F469B4E195C59FC25D8F4F8C79 /* RLMSchema_Private.h in Copy . Private Headers */, + 9C20856EDF5A9D048A25A0E5E6C4D6EC /* RLMSet_Private.h in Copy . Private Headers */, + 9D088891C4077B7C96B4626A7C9C0113 /* RLMSwiftProperty.h in Copy . Private Headers */, + F48BBB342D22A1EE7AC2508682F827AE /* RLMSyncConfiguration_Private.h in Copy . Private Headers */, + 5858E83F858272F084A4B75F0C01DFBF /* RLMSyncSubscription_Private.h in Copy . Private Headers */, + E8E68A15275FD6942B3345A9CD29D237 /* RLMUser_Private.h in Copy . Private Headers */, + ); + name = "Copy . Private Headers"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 017195EB54DBECB50C413EB1A820E94D /* RLMLogger.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMLogger.mm; path = Realm/RLMLogger.mm; sourceTree = ""; }; + 02BCC49FB1F90CE18788E9C8DF1F60C9 /* SortDescriptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SortDescriptor.swift; path = RealmSwift/SortDescriptor.swift; sourceTree = ""; }; + 084EDB73408D5ED54E37CC7A8193791C /* Pods-BremerTests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-BremerTests-umbrella.h"; sourceTree = ""; }; + 0900DCBD41747C1B1D6A5D788E7F4134 /* Realm-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Realm-Info.plist"; sourceTree = ""; }; + 0AF05C6D9B63DCA0A6436D62E942292E /* RLMSyncManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncManager.h; path = include/RLMSyncManager.h; sourceTree = ""; }; + 0EC784486BA2B84E7CC5BF4FFE73B033 /* RLMClassInfo.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMClassInfo.mm; path = Realm/RLMClassInfo.mm; sourceTree = ""; }; + 0F6AE9474A96853A8CCEB7217E7882B1 /* RLMObjectBase_Dynamic.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectBase_Dynamic.h; path = include/RLMObjectBase_Dynamic.h; sourceTree = ""; }; + 1093D1C3E0121F776B90F3F425A05747 /* RLMEmbeddedObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMEmbeddedObject.h; path = include/RLMEmbeddedObject.h; sourceTree = ""; }; + 128E2A3A408DD8C462D655821E17014B /* RLMObjectSchema.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMObjectSchema.mm; path = Realm/RLMObjectSchema.mm; sourceTree = ""; }; + 12E0802B8D1CD4C7F7B06EB8B6161352 /* RLMAPIKeyAuth.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMAPIKeyAuth.mm; path = Realm/RLMAPIKeyAuth.mm; sourceTree = ""; }; + 14E5074693C241E739C0F88EA9E26D6E /* RLMRealm_Dynamic.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealm_Dynamic.h; path = include/RLMRealm_Dynamic.h; sourceTree = ""; }; + 156B0F1647DE46158BC285E80693AC3F /* RLMProperty.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMProperty.h; path = include/RLMProperty.h; sourceTree = ""; }; + 156DA493B9D89EC4212074D2C995EF9C /* RLMObject_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObject_Private.h; path = include/RLMObject_Private.h; sourceTree = ""; }; + 15AFE66B86114D491B00DFE510CC6081 /* RLMAsymmetricObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMAsymmetricObject.h; path = include/RLMAsymmetricObject.h; sourceTree = ""; }; + 170BFD8D6212C2BE4613E8915FE93911 /* RLMApp.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMApp.h; path = include/RLMApp.h; sourceTree = ""; }; + 17BF8FF42BA0F44D5871BF66E11034C6 /* Realm.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Realm.release.xcconfig; sourceTree = ""; }; + 1936DA062F9BE3920D47A14C3DD4851C /* RLMBSON.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMBSON.h; path = include/RLMBSON.h; sourceTree = ""; }; + 1A7E1E1F583157E97280C2C11F60253D /* RLMRealmUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMRealmUtil.mm; path = Realm/RLMRealmUtil.mm; sourceTree = ""; }; + 1AF58B2A8E5F1848F36BD2D6637AC585 /* RLMObjectBase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectBase.h; path = include/RLMObjectBase.h; sourceTree = ""; }; + 1B300F080FDE47388D3EB31854C9C2C8 /* Pods-Bremer-BremerUITests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Bremer-BremerUITests-dummy.m"; sourceTree = ""; }; + 1B7374F60D29EB95FE8F0B6E7BC6981C /* Combine.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Combine.swift; path = RealmSwift/Combine.swift; sourceTree = ""; }; + 1D7A1F605D5891D44CC5D45CB5309EC8 /* RLMNetworkTransport.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMNetworkTransport.mm; path = Realm/RLMNetworkTransport.mm; sourceTree = ""; }; + 1DC6D46B721373B7304BAA683AF6093A /* Realm.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Realm.debug.xcconfig; sourceTree = ""; }; + 1DC8B026FE1FDFCF15381976F1111E6F /* Pods-Bremer.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-Bremer.modulemap"; sourceTree = ""; }; + 1EB3A9E52A23FB3F9B23BBF63DD7653A /* RLMSwiftSupport.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RLMSwiftSupport.m; path = Realm/RLMSwiftSupport.m; sourceTree = ""; }; + 202E9650F11F6AD66598EC94505C0DC0 /* RLMQueryUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMQueryUtil.mm; path = Realm/RLMQueryUtil.mm; sourceTree = ""; }; + 20F8BD3214B20EF37E8F662ACCAAA60C /* RLMMongoCollection_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMongoCollection_Private.h; path = include/RLMMongoCollection_Private.h; sourceTree = ""; }; + 21A3950C70D95063F4AA9D6404705A82 /* PropertyAccessors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PropertyAccessors.swift; path = RealmSwift/Impl/PropertyAccessors.swift; sourceTree = ""; }; + 23D58A0A4DF4703C125A90D1398E776E /* RLMPushClient.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMPushClient.mm; path = Realm/RLMPushClient.mm; sourceTree = ""; }; + 251F62CD7F86A4BDC5A5251E2EC9CDE5 /* RLMSwiftObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSwiftObject.h; path = include/RLMSwiftObject.h; sourceTree = ""; }; + 287A198FE10ED2E080F841D672EEB650 /* RLMObjectStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectStore.h; path = include/RLMObjectStore.h; sourceTree = ""; }; + 28BDE71E985AC8FBF505AD02C4B30C06 /* RLMThreadSafeReference.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMThreadSafeReference.h; path = include/RLMThreadSafeReference.h; sourceTree = ""; }; + 2B9DEE7FCD724E8946C81F8A781486E9 /* RLMObservation.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMObservation.mm; path = Realm/RLMObservation.mm; sourceTree = ""; }; + 2D9C769A591C3C701C4B3D66805689FD /* RLMUserAPIKey.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMUserAPIKey.mm; path = Realm/RLMUserAPIKey.mm; sourceTree = ""; }; + 2DF39689A0A6790771DC1773757C1EAF /* RealmProperty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RealmProperty.swift; path = RealmSwift/RealmProperty.swift; sourceTree = ""; }; + 2F48A095DE75F551D2309337016C13BC /* Pods-Bremer-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Bremer-frameworks.sh"; sourceTree = ""; }; + 2F6C9E50FB69103202B6E5F4AD647AAB /* RLMApp_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMApp_Private.h; path = include/RLMApp_Private.h; sourceTree = ""; }; + 308DBDE082D41F22F50C92F0219C0282 /* RLMDictionary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMDictionary.h; path = include/RLMDictionary.h; sourceTree = ""; }; + 31A8F30D8D7E0AB02362EE0AD1AF1268 /* RLMSyncSubscription_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncSubscription_Private.h; path = include/RLMSyncSubscription_Private.h; sourceTree = ""; }; + 31ADBCF4BF2601BDCF3BEB00B234A65A /* RLMSyncConfiguration_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncConfiguration_Private.h; path = include/RLMSyncConfiguration_Private.h; sourceTree = ""; }; + 3242E2AFF0DE901E8DB25964E6FCA10E /* RLMEmailPasswordAuth.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMEmailPasswordAuth.h; path = include/RLMEmailPasswordAuth.h; sourceTree = ""; }; + 328DA24E2F0FFF97F378C482A57756A6 /* RLMSet.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSet.mm; path = Realm/RLMSet.mm; sourceTree = ""; }; + 3420BCC96784716342E7EED0676CA699 /* RealmSwift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RealmSwift.release.xcconfig; sourceTree = ""; }; + 35F8E3BFFB37BB4E8E5F5ABBEE1922B4 /* Realm-xcframeworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Realm-xcframeworks.sh"; sourceTree = ""; }; + 36DA7DE9E336E47CEB58E15845B6188C /* RLMMongoCollection.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMMongoCollection.mm; path = Realm/RLMMongoCollection.mm; sourceTree = ""; }; + 383925AD60D374AAD8AE07ED633D8731 /* Sync.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sync.swift; path = RealmSwift/Sync.swift; sourceTree = ""; }; + 394000ACEC3525AB18794B5B44ECED44 /* Property.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Property.swift; path = RealmSwift/Property.swift; sourceTree = ""; }; + 3A122237AC82FC67FCCBBC7B49CF3B6F /* RLMRealm.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealm.h; path = include/RLMRealm.h; sourceTree = ""; }; + 3AE9917146111B7CF81BE6A9EA9097B7 /* Schema.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Schema.swift; path = RealmSwift/Schema.swift; sourceTree = ""; }; + 3C6F253DE442B7CD2596F4212103F666 /* RLMSyncSession.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncSession.h; path = include/RLMSyncSession.h; sourceTree = ""; }; + 3CDDCAA2E3900E5AF247A6EBAED2B0FC /* Pods-Bremer-BremerUITests */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-Bremer-BremerUITests"; path = Pods_Bremer_BremerUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3DF0FA1A97FC74EF390C53A21A64F68A /* Pods-Bremer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Bremer.debug.xcconfig"; sourceTree = ""; }; + 3E07A833E0493B8D3F6A88C794F249EA /* RLMArray.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMArray.mm; path = Realm/RLMArray.mm; sourceTree = ""; }; + 3E72B23F2A49F29F16A02EFFA295F479 /* Results.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Results.swift; path = RealmSwift/Results.swift; sourceTree = ""; }; + 3E8354B5E993B479A2BC6DD30FBC6F75 /* RLMSwiftValueStorage.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSwiftValueStorage.mm; path = Realm/RLMSwiftValueStorage.mm; sourceTree = ""; }; + 3EE21D373515813C8D8187A7DB408B8F /* RLMCollection_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMCollection_Private.h; path = include/RLMCollection_Private.h; sourceTree = ""; }; + 3FD6D5AC2A4EDD998FDAE19520FB6DA8 /* KeyPathStrings.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KeyPathStrings.swift; path = RealmSwift/Impl/KeyPathStrings.swift; sourceTree = ""; }; + 407AB4F6922BDF4346E500A6611B2925 /* RLMConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMConstants.h; path = include/RLMConstants.h; sourceTree = ""; }; + 42C86ED21C9DEA623DAFDDF386C44A42 /* Query.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Query.swift; path = RealmSwift/Query.swift; sourceTree = ""; }; + 437919EE08EC6BFCCBAC3BD346309742 /* RealmSwift */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = RealmSwift; path = RealmSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 438EEDFCDE953A0FB47AF574D22EB312 /* RLMObject.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMObject.mm; path = Realm/RLMObject.mm; sourceTree = ""; }; + 43C6952CC7740B9F3AFD6D7C5FBB1472 /* RLMProperty.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMProperty.mm; path = Realm/RLMProperty.mm; sourceTree = ""; }; + 44510D341917737F55D98E6E9746CB05 /* RealmSwift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RealmSwift.debug.xcconfig; sourceTree = ""; }; + 44B69D33543C8F54BB506C2BDA32BCBF /* RLMManagedSet.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMManagedSet.mm; path = Realm/RLMManagedSet.mm; sourceTree = ""; }; + 44BE1AE28CD9E51D7A284CB0F4570743 /* RLMSchema.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSchema.h; path = include/RLMSchema.h; sourceTree = ""; }; + 45E82184D579BFB3425818E1CD186CF1 /* RLMSyncSession.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSyncSession.mm; path = Realm/RLMSyncSession.mm; sourceTree = ""; }; + 47F9EF2D06DD5F0C3364A50CFFD27175 /* MutableSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MutableSet.swift; path = RealmSwift/MutableSet.swift; sourceTree = ""; }; + 49B40BC6C081C021D6AF3122D256E52C /* Pods-Bremer */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-Bremer"; path = Pods_Bremer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4C09B309CFB80885122EC89B6624AA54 /* RLMSwiftCollectionBase.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSwiftCollectionBase.mm; path = Realm/RLMSwiftCollectionBase.mm; sourceTree = ""; }; + 4C8CB92E182DD4E1C1396D71933EFB15 /* Pods-BremerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-BremerTests.release.xcconfig"; sourceTree = ""; }; + 4D53E2B9DA57CF465830EC92CE38FEA7 /* RLMAsyncTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMAsyncTask.h; path = include/RLMAsyncTask.h; sourceTree = ""; }; + 4DDAFDDCA2217B2266A2A7953A11B8C8 /* RLMCollection.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMCollection.mm; path = Realm/RLMCollection.mm; sourceTree = ""; }; + 4E1819A1DE7516208F40BA9103184CB9 /* RLMRealm_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealm_Private.h; path = include/RLMRealm_Private.h; sourceTree = ""; }; + 4F7EFF56DEE55B0043740912E928BE2B /* Error.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Error.swift; path = RealmSwift/Error.swift; sourceTree = ""; }; + 5048457FAC7400CC15E9FF5E34CC736B /* RLMRealmConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealmConfiguration.h; path = include/RLMRealmConfiguration.h; sourceTree = ""; }; + 50C117353A5193CCEC27DB1764BCCEE3 /* RLMError.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMError.mm; path = Realm/RLMError.mm; sourceTree = ""; }; + 50C62D1CB8E06C6160D58D4DE83CA25E /* Pods-Bremer-BremerUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Bremer-BremerUITests.debug.xcconfig"; sourceTree = ""; }; + 5376A112937007DC01BCE9F6BF1A81F0 /* RealmSwift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RealmSwift.modulemap; sourceTree = ""; }; + 53B53BC95B8BCEB3A967BBFB997E527C /* Pods-BremerTests */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-BremerTests"; path = Pods_BremerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 53FEC31B25442C280C915CF78B83081E /* RLMCollection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMCollection.h; path = include/RLMCollection.h; sourceTree = ""; }; + 54929AAB01C9B10B946F41FBDF583DF4 /* Pods-BremerTests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-BremerTests-dummy.m"; sourceTree = ""; }; + 54D7D00A08CA47ADDD2F30482CD74CA4 /* Pods-Bremer-BremerUITests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Bremer-BremerUITests-Info.plist"; sourceTree = ""; }; + 5541E31DC0879051FFC3C4EE04F765B9 /* RLMResults_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMResults_Private.h; path = include/RLMResults_Private.h; sourceTree = ""; }; + 55CA65AB80B992F7E3314562911526F9 /* Pods-Bremer-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Bremer-acknowledgements.plist"; sourceTree = ""; }; + 56900CC788B27223518F048DAECC2413 /* RLMSchema.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSchema.mm; path = Realm/RLMSchema.mm; sourceTree = ""; }; + 56DEB3241033B81B56C42516B00EAF55 /* Pods-BremerTests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-BremerTests.modulemap"; sourceTree = ""; }; + 58E58D6C4EE9BB5E393E64A3A8B042B0 /* RLMFindOneAndModifyOptions.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMFindOneAndModifyOptions.mm; path = Realm/RLMFindOneAndModifyOptions.mm; sourceTree = ""; }; + 590D63CB0677446E02281D23D4692E4C /* RLMApp.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMApp.mm; path = Realm/RLMApp.mm; sourceTree = ""; }; + 5AA3DBC5397A141FB8A3B336E0C3CA72 /* RLMEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMEvent.h; path = include/RLMEvent.h; sourceTree = ""; }; + 5AF7E94666A9B45384AB13E181E4CD57 /* NSError+RLMSync.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSError+RLMSync.h"; path = "include/NSError+RLMSync.h"; sourceTree = ""; }; + 5B3843DC404B5980821B936973765690 /* Pods-Bremer-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Bremer-acknowledgements.markdown"; sourceTree = ""; }; + 5B57CFF0C89A929D0188B77FF91CB915 /* RealmCollection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RealmCollection.swift; path = RealmSwift/RealmCollection.swift; sourceTree = ""; }; + 5E96A87D4C9F5DE31C5D4A08F2B80B71 /* Realm-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Realm-dummy.m"; sourceTree = ""; }; + 5EC5EE6912182E015407E574294ABDCC /* ComplexTypes.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ComplexTypes.swift; path = RealmSwift/Impl/ComplexTypes.swift; sourceTree = ""; }; + 62714ACEE2FB404ECB36352920522B4B /* Pods-BremerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-BremerTests.debug.xcconfig"; sourceTree = ""; }; + 630D71BD599B166A03AF9F122A664074 /* Pods-BremerTests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-BremerTests-acknowledgements.plist"; sourceTree = ""; }; + 6446CF5660FCF90AA0617D6B16C9B7E2 /* RLMUser.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMUser.mm; path = Realm/RLMUser.mm; sourceTree = ""; }; + 656A2602114C6F39008996487E53F025 /* RLMValue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMValue.h; path = include/RLMValue.h; sourceTree = ""; }; + 67092FC5F8649E5A26AE847AD8A8876D /* ThreadSafeReference.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ThreadSafeReference.swift; path = RealmSwift/ThreadSafeReference.swift; sourceTree = ""; }; + 68B7ABFB3FB23D05DCFCBD5E4F60D8C1 /* RLMPushClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMPushClient.h; path = include/RLMPushClient.h; sourceTree = ""; }; + 68D58FC196381235BC49DEF871BC6C4E /* RLMSyncSubscription.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncSubscription.h; path = include/RLMSyncSubscription.h; sourceTree = ""; }; + 6925048E7FF653A3F7FDA6C80603546F /* RLMProperty_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMProperty_Private.h; path = include/RLMProperty_Private.h; sourceTree = ""; }; + 695219F6ABA376C2FD4EDABC626FA786 /* RLMObjectStore.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMObjectStore.mm; path = Realm/RLMObjectStore.mm; sourceTree = ""; }; + 6983861E2027D12D1EE3509BFA276CDC /* RLMUser.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMUser.h; path = include/RLMUser.h; sourceTree = ""; }; + 6B4DD113336EDCBA8E57663DAC98DAED /* ObjectiveCSupport+AnyRealmValue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObjectiveCSupport+AnyRealmValue.swift"; path = "RealmSwift/ObjectiveCSupport+AnyRealmValue.swift"; sourceTree = ""; }; + 6FE040B999F510C22305E6F3F81FDB1E /* Pods-Bremer.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Bremer.release.xcconfig"; sourceTree = ""; }; + 7002EA128EE9AD22020152C5C6894C5F /* Pods-Bremer-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Bremer-dummy.m"; sourceTree = ""; }; + 70D19506168EA3B184AB2365D7D7C50D /* RealmSwift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RealmSwift-dummy.m"; sourceTree = ""; }; + 71F72372D406C3B51B6B52160127CAFA /* BSON.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BSON.swift; path = RealmSwift/BSON.swift; sourceTree = ""; }; + 72BBEB735A09A89265B342D9D00DD130 /* RLMSchema_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSchema_Private.h; path = include/RLMSchema_Private.h; sourceTree = ""; }; + 72CC1F1C755FBC3CF1BAA38D53EE2BE1 /* RLMDictionary_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMDictionary_Private.h; path = include/RLMDictionary_Private.h; sourceTree = ""; }; + 7382B395581C4D5173DD3D9F1FA73E6E /* RLMMongoCollection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMongoCollection.h; path = include/RLMMongoCollection.h; sourceTree = ""; }; + 748B44A932F1CC48BB670ED0D3ACC753 /* RLMAsymmetricObject.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMAsymmetricObject.mm; path = Realm/RLMAsymmetricObject.mm; sourceTree = ""; }; + 757457E7DEA8C2AA02BAF76C46377329 /* RLMObjectSchema_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectSchema_Private.h; path = include/RLMObjectSchema_Private.h; sourceTree = ""; }; + 78238DD3B0F804A47333BC5B45487E9C /* Aliases.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Aliases.swift; path = RealmSwift/Aliases.swift; sourceTree = ""; }; + 79249BAC9D61B8D7B94CCE8A8E5760C6 /* RealmSwift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RealmSwift-umbrella.h"; sourceTree = ""; }; + 799DEF74847E011F991ED851F8FB9AD5 /* EmbeddedObject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = EmbeddedObject.swift; path = RealmSwift/EmbeddedObject.swift; sourceTree = ""; }; + 79B0FE938D2F799ECCA6EDFA678A1B91 /* MongoClient.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MongoClient.swift; path = RealmSwift/MongoClient.swift; sourceTree = ""; }; + 7AB66F45F8EDDFF03F80FCC411B39AAF /* RLMFindOneAndModifyOptions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMFindOneAndModifyOptions.h; path = include/RLMFindOneAndModifyOptions.h; sourceTree = ""; }; + 7AFFB0657BB0ABFDBE61C1E243296B0A /* RLMProviderClient.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMProviderClient.mm; path = Realm/RLMProviderClient.mm; sourceTree = ""; }; + 7B3CD4A2BD648DA78AC6D18274B7B3BE /* ObjectSchema.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObjectSchema.swift; path = RealmSwift/ObjectSchema.swift; sourceTree = ""; }; + 7B9D2B248DEA4041A5D5652F4C370372 /* RLMSyncSubscription.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSyncSubscription.mm; path = Realm/RLMSyncSubscription.mm; sourceTree = ""; }; + 7BCF4F4DFBF323D1F496E7AA905F6829 /* AsymmetricObject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsymmetricObject.swift; path = RealmSwift/AsymmetricObject.swift; sourceTree = ""; }; + 7BD82FB62C4C6F66BB1E560622D260E1 /* RLMAsyncTask.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMAsyncTask.mm; path = Realm/RLMAsyncTask.mm; sourceTree = ""; }; + 7CCBCA3A7CCA35C254E7412CD7B5C33B /* Optional.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Optional.swift; path = RealmSwift/Optional.swift; sourceTree = ""; }; + 7EBA5CFE49DBE74E402A458118E45875 /* RLMConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RLMConstants.m; path = Realm/RLMConstants.m; sourceTree = ""; }; + 8096A6CE2B47313736FA293317A1947C /* RLMSwiftCollectionBase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSwiftCollectionBase.h; path = include/RLMSwiftCollectionBase.h; sourceTree = ""; }; + 82C5C50748116066982FC9D2A840A226 /* RealmSwift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RealmSwift-prefix.pch"; sourceTree = ""; }; + 8309845A98031BE7C80BC7899D47FE76 /* RLMSyncConfiguration.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSyncConfiguration.mm; path = Realm/RLMSyncConfiguration.mm; sourceTree = ""; }; + 843867735B0F568A533F9046851F6464 /* Pods-Bremer-BremerUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Bremer-BremerUITests.release.xcconfig"; sourceTree = ""; }; + 84A6961C92C6C022D5E9CC07787774CC /* Util.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Util.swift; path = RealmSwift/Util.swift; sourceTree = ""; }; + 8503B74C1678228FF9FC0BA42CE15096 /* RLMUserAPIKey.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMUserAPIKey.h; path = include/RLMUserAPIKey.h; sourceTree = ""; }; + 8665FB3F64D1560D6687B39D7E65A68F /* RLMScheduler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMScheduler.h; path = include/RLMScheduler.h; sourceTree = ""; }; + 86C82009901EC92F1F93D8D4E50B2632 /* RLMMongoDatabase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMongoDatabase.h; path = include/RLMMongoDatabase.h; sourceTree = ""; }; + 8929353C9A521D1515E318601DB0459F /* RLMThreadSafeReference.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMThreadSafeReference.mm; path = Realm/RLMThreadSafeReference.mm; sourceTree = ""; }; + 89578087225F22AF21C2C253BD9F15E7 /* RLMUpdateResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMUpdateResult.h; path = include/RLMUpdateResult.h; sourceTree = ""; }; + 8B31DC02061BD43612D97809BBE8BF74 /* RLMArray_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMArray_Private.h; path = include/RLMArray_Private.h; sourceTree = ""; }; + 8BF652086B82FCB285AF95A331F06874 /* RLMRealm+Sync.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "RLMRealm+Sync.h"; path = "include/RLMRealm+Sync.h"; sourceTree = ""; }; + 8C04C9768E31A75ACAEE02BD5B6CC754 /* RealmConfiguration.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RealmConfiguration.swift; path = RealmSwift/RealmConfiguration.swift; sourceTree = ""; }; + 8D260A52C53254A6FF21693A13B6D241 /* RLMCredentials.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMCredentials.h; path = include/RLMCredentials.h; sourceTree = ""; }; + 8DD5C52ED1637C35CFF24F78FA8E7F34 /* PersistedProperty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PersistedProperty.swift; path = RealmSwift/PersistedProperty.swift; sourceTree = ""; }; + 8F40C24E83BF14942C1ECD9977BED25A /* RLMManagedArray.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMManagedArray.mm; path = Realm/RLMManagedArray.mm; sourceTree = ""; }; + 9049A1739CCEC574D7F368AAF96BC20D /* LinkingObjects.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LinkingObjects.swift; path = RealmSwift/LinkingObjects.swift; sourceTree = ""; }; + 921BE4A82C4A7A5C72A0C6F8B8FEF200 /* Realm */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Realm; path = Realm.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 92DC24CEF1BFE8D67401AA89AE318EAB /* CollectionAccess.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CollectionAccess.swift; path = RealmSwift/Impl/CollectionAccess.swift; sourceTree = ""; }; + 931FFD633662A9674B8F3EF39579EB5C /* RLMUser_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMUser_Private.h; path = include/RLMUser_Private.h; sourceTree = ""; }; + 952925E838A0DE4D7BDC4EE54022633D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + 955AB3E9C7A92CB2C66930D1B7A9F8EE /* CustomPersistable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CustomPersistable.swift; path = RealmSwift/CustomPersistable.swift; sourceTree = ""; }; + 966AE395BC3B71F90831AFE79586D893 /* RLMCredentials.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMCredentials.mm; path = Realm/RLMCredentials.mm; sourceTree = ""; }; + 97803D1FC1CC8551BE103980CD22B5E9 /* RLMSwiftValueStorage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSwiftValueStorage.h; path = include/RLMSwiftValueStorage.h; sourceTree = ""; }; + 97ACC83057F43D9B6980F6F7C750B9DF /* RLMLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMLogger.h; path = include/RLMLogger.h; sourceTree = ""; }; + 98406ED6D7929CB5C414D49E3028B995 /* RLMDictionary.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMDictionary.mm; path = Realm/RLMDictionary.mm; sourceTree = ""; }; + 98A99A950E295F01B3CE7F2FBBEBC429 /* RLMSwiftProperty.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSwiftProperty.h; path = include/RLMSwiftProperty.h; sourceTree = ""; }; + 98E948B5C4D15AEC19AA92F80B2AFC28 /* RLMResults.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMResults.mm; path = Realm/RLMResults.mm; sourceTree = ""; }; + 99AA99D23861CC51BB876FA7CDEAE774 /* RLMRealmConfiguration_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealmConfiguration_Private.h; path = include/RLMRealmConfiguration_Private.h; sourceTree = ""; }; + 9A80C850252DD65379ADE04815FEA92E /* App.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = App.swift; path = RealmSwift/App.swift; sourceTree = ""; }; + 9CF79020CE57ECA510B1E580B1CE98E5 /* RLMRealm.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMRealm.mm; path = Realm/RLMRealm.mm; sourceTree = ""; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + A00386484AF93B1D69A5F465564FF33F /* Events.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Events.swift; path = RealmSwift/Events.swift; sourceTree = ""; }; + A07078F84B897764F4F56E9E30C2AED9 /* RLMProviderClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMProviderClient.h; path = include/RLMProviderClient.h; sourceTree = ""; }; + A26ED6EDF207AA276CBAD6DED2156D8E /* RLMPredicateUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMPredicateUtil.mm; path = Realm/RLMPredicateUtil.mm; sourceTree = ""; }; + A418A33CBA33C7CA3777D174F9A7F6E3 /* RLMRealmConfiguration.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMRealmConfiguration.mm; path = Realm/RLMRealmConfiguration.mm; sourceTree = ""; }; + A5C44617F54A134E586D8A6138AEBF85 /* Realm.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Realm.swift; path = RealmSwift/Realm.swift; sourceTree = ""; }; + A5CD3E27F8461649EAEFA0D4C6F00E51 /* SectionedResults.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SectionedResults.swift; path = RealmSwift/SectionedResults.swift; sourceTree = ""; }; + A6954DA60DEE09E47284DFB14176FC5C /* RLMMongoClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMongoClient.h; path = include/RLMMongoClient.h; sourceTree = ""; }; + A8F9AABF7EF41FAC511573B7DD1CE8F7 /* Pods-BremerTests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-BremerTests-Info.plist"; sourceTree = ""; }; + A9C89270B39D91E8A818E34F32C7799A /* RLMSyncConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncConfiguration.h; path = include/RLMSyncConfiguration.h; sourceTree = ""; }; + AEF5520981A82480A9E8725B47C709F1 /* RLMLogger_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMLogger_Private.h; path = include/RLMLogger_Private.h; sourceTree = ""; }; + AF06966964C0E0BF8DDBC044F35434E6 /* RLMAsyncTask_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMAsyncTask_Private.h; path = include/RLMAsyncTask_Private.h; sourceTree = ""; }; + AFBAAA7D9AF1F57EA8E05B3BB9ED1F8D /* RLMAccessor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMAccessor.h; path = include/RLMAccessor.h; sourceTree = ""; }; + B1FFADEF337AAEECCB0F4A9EB0364182 /* Pods-BremerTests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-BremerTests-acknowledgements.markdown"; sourceTree = ""; }; + B275916C09492961BE9FF64C026D7D5B /* Object.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Object.swift; path = RealmSwift/Object.swift; sourceTree = ""; }; + B2B3CF7C7D1F83C09082DF1C6AFB0159 /* RLMDecimal128.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMDecimal128.mm; path = Realm/RLMDecimal128.mm; sourceTree = ""; }; + B6C0D5B885BBC7CEECB041828C3C09E3 /* Realm-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Realm-prefix.pch"; sourceTree = ""; }; + B74909372FE229B46DB6568F865259B3 /* RLMObjectBase.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMObjectBase.mm; path = Realm/RLMObjectBase.mm; sourceTree = ""; }; + B86B0CF4D89A205EC9854F54BD415F81 /* NSError+RLMSync.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSError+RLMSync.m"; path = "Realm/NSError+RLMSync.m"; sourceTree = ""; }; + BA42A0E2BDA802CD41C5791B01D95C8A /* RLMSet.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSet.h; path = include/RLMSet.h; sourceTree = ""; }; + BC2DDB1B7EB185FFE2B8E387885B7842 /* BasicTypes.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BasicTypes.swift; path = RealmSwift/Impl/BasicTypes.swift; sourceTree = ""; }; + BCF15A7FAB1BAB6CF87FA1E1240EAA22 /* RLMAccessor.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMAccessor.mm; path = Realm/RLMAccessor.mm; sourceTree = ""; }; + BDBB744BDFC26FF83B92E27D104894BA /* SyncSubscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SyncSubscription.swift; path = RealmSwift/SyncSubscription.swift; sourceTree = ""; }; + BE989A32E4CB9545DF1C960611306231 /* RLMValue.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMValue.mm; path = Realm/RLMValue.mm; sourceTree = ""; }; + BEB90A9D28C866141E369004C2BAE05D /* Realm.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = Realm.modulemap; sourceTree = ""; }; + BF1DA4828D80F3F4FB062A05B6839473 /* RLMObjectBase_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectBase_Private.h; path = include/RLMObjectBase_Private.h; sourceTree = ""; }; + BF970CC730D7528B9F16B94716554C85 /* RLMSyncManager.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSyncManager.mm; path = Realm/RLMSyncManager.mm; sourceTree = ""; }; + C0004D5E5EFD0B9DB132A9665F5722ED /* RLMUpdateChecker.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMUpdateChecker.mm; path = Realm/RLMUpdateChecker.mm; sourceTree = ""; }; + C0040FBF8247CDC8C0A0291B31DB2C6E /* RLMSectionedResults.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSectionedResults.mm; path = Realm/RLMSectionedResults.mm; sourceTree = ""; }; + C2FC7E591096B5B21551F74E7DE51CDD /* RLMRealm+Sync.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = "RLMRealm+Sync.mm"; path = "Realm/RLMRealm+Sync.mm"; sourceTree = ""; }; + C3B2A0B779CE31153B2C0D8A7F8DC7FE /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + C504BA8B8FBFE75AEFA8B3799B0A4184 /* RealmSwift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RealmSwift-Info.plist"; sourceTree = ""; }; + C6CDC4F0BC0FEF0BF1EDAFBE780C3FC0 /* RLMEmbeddedObject.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMEmbeddedObject.mm; path = Realm/RLMEmbeddedObject.mm; sourceTree = ""; }; + C9164561687AF22B091FF5B25D0D938A /* RLMSupport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RLMSupport.swift; path = Realm/Swift/RLMSupport.swift; sourceTree = ""; }; + C9F7B3C67C23767E4B2FFBC5E3131FA8 /* Decimal128.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Decimal128.swift; path = RealmSwift/Decimal128.swift; sourceTree = ""; }; + CB1FDB7543E2546535D25285A7CDCE2C /* Pods-Bremer-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Bremer-umbrella.h"; sourceTree = ""; }; + CD4D935A3B6C8A82ADB9DF7455DFB90B /* RLMSet_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSet_Private.h; path = include/RLMSet_Private.h; sourceTree = ""; }; + CDAF7E43CDAEE6A562D7DE73E48BBD34 /* Map.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Map.swift; path = RealmSwift/Map.swift; sourceTree = ""; }; + CEFA3AA5A6F13EF14DC0485AA3C77E26 /* RLMManagedDictionary.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMManagedDictionary.mm; path = Realm/RLMManagedDictionary.mm; sourceTree = ""; }; + CF24E6101AE36BCE037294AB302C146B /* Pods-Bremer-BremerUITests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Bremer-BremerUITests-umbrella.h"; sourceTree = ""; }; + CF2A69713E0A59C06190FA785F2973F0 /* Pods-Bremer-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Bremer-Info.plist"; sourceTree = ""; }; + CF895822EEC64C38157631A6BFD04142 /* Pods-Bremer-BremerUITests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Bremer-BremerUITests-acknowledgements.markdown"; sourceTree = ""; }; + D0A8A01C6E0F577E45980964BB353E35 /* RLMObjectSchema.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectSchema.h; path = include/RLMObjectSchema.h; sourceTree = ""; }; + D31E3586B5A91CF716C4428503A3CFCD /* RLMScheduler.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMScheduler.mm; path = Realm/RLMScheduler.mm; sourceTree = ""; }; + D33AC4A4F700EB53303DA72A42DADD96 /* RLMSectionedResults.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSectionedResults.h; path = include/RLMSectionedResults.h; sourceTree = ""; }; + D3468C0BF4B4320A39D25D9CE6584A26 /* RLMUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMUtil.mm; path = Realm/RLMUtil.mm; sourceTree = ""; }; + D3A44DB03BC89613444A8677AF8B9718 /* ObjectiveCSupport+BSON.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObjectiveCSupport+BSON.swift"; path = "RealmSwift/ObjectiveCSupport+BSON.swift"; sourceTree = ""; }; + D43F5F1C05A626BF68E6115C5309DE07 /* RLMUUID.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMUUID.mm; path = Realm/RLMUUID.mm; sourceTree = ""; }; + D6125B0B3BCF1040E9B3A78EB5EDF928 /* RLMBSON.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMBSON.mm; path = Realm/RLMBSON.mm; sourceTree = ""; }; + D84BC124274D8FFAD5233B64FF3CAC3E /* AnyRealmValue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnyRealmValue.swift; path = RealmSwift/AnyRealmValue.swift; sourceTree = ""; }; + DB2B37C3887EC2A789C5465BD724856A /* List.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = List.swift; path = RealmSwift/List.swift; sourceTree = ""; }; + DC906F177DFF762E0F2E2A4095889CFE /* RLMError.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMError.h; path = include/RLMError.h; sourceTree = ""; }; + DD5F9555DB50862C43611118F9E6FF20 /* RLMEvent.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMEvent.mm; path = Realm/RLMEvent.mm; sourceTree = ""; }; + DD6CF5C22D43D0340212EFD3A0341BE7 /* RLMNetworkTransport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMNetworkTransport.h; path = include/RLMNetworkTransport.h; sourceTree = ""; }; + DF207A2F226C16092CB5DB8515FC4F50 /* RLMUpdateResult.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMUpdateResult.mm; path = Realm/RLMUpdateResult.mm; sourceTree = ""; }; + DF65E0CB75B86CAF5232510BF6C5994E /* RLMFindOptions.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMFindOptions.mm; path = Realm/RLMFindOptions.mm; sourceTree = ""; }; + DFABC7F89E109F6B72CC258AC4F2DB95 /* RLMEmailPasswordAuth.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMEmailPasswordAuth.mm; path = Realm/RLMEmailPasswordAuth.mm; sourceTree = ""; }; + E003BD497C568C08EC768CD231F1AD26 /* RLMObjectId.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectId.h; path = include/RLMObjectId.h; sourceTree = ""; }; + E07BC5BBA223584E52693AAB962FD0C1 /* RealmCollectionImpl.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RealmCollectionImpl.swift; path = RealmSwift/Impl/RealmCollectionImpl.swift; sourceTree = ""; }; + E2902657D4B3DF4F908B849A1F5FFD8F /* RLMFindOptions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMFindOptions.h; path = include/RLMFindOptions.h; sourceTree = ""; }; + E3F27588B6819F964CCE16A4A87A0B84 /* RLMResults.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMResults.h; path = include/RLMResults.h; sourceTree = ""; }; + E546E812630FC30731574AD839131FA7 /* RLMAnalytics.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMAnalytics.mm; path = Realm/RLMAnalytics.mm; sourceTree = ""; }; + E57599782133BDF9EB8C7DFCEC56D992 /* ObjcBridgeable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObjcBridgeable.swift; path = RealmSwift/Impl/ObjcBridgeable.swift; sourceTree = ""; }; + E5D51CF7CC72E3E01269B1108CD73D9A /* RLMDecimal128.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMDecimal128.h; path = include/RLMDecimal128.h; sourceTree = ""; }; + E8B20DE7B2DD404FF067CCBD44C1DF16 /* Pods-Bremer-BremerUITests-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Bremer-BremerUITests-frameworks.sh"; sourceTree = ""; }; + E9E53F66B8F189AD9580AE5C05FB1D28 /* ObjectiveCSupport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObjectiveCSupport.swift; path = RealmSwift/ObjectiveCSupport.swift; sourceTree = ""; }; + ED205C636A7332EDE1203A29F356F902 /* ObjectId.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObjectId.swift; path = RealmSwift/ObjectId.swift; sourceTree = ""; }; + EF36B120935792B4001A5634115A5AE9 /* SchemaDiscovery.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SchemaDiscovery.swift; path = RealmSwift/Impl/SchemaDiscovery.swift; sourceTree = ""; }; + EFEE93CEA5E067B5DCFE4B87C2F14B73 /* Persistable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Persistable.swift; path = RealmSwift/Impl/Persistable.swift; sourceTree = ""; }; + F0CA69915FC0A9DE4556DCAC4009F263 /* RLMMigration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMigration.h; path = include/RLMMigration.h; sourceTree = ""; }; + F1112374050461D3B924DCD64699FED3 /* Pods-Bremer-BremerUITests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Bremer-BremerUITests-acknowledgements.plist"; sourceTree = ""; }; + F123E905A47AB485FEE2C2B6188D39A5 /* RLMObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObject.h; path = include/RLMObject.h; sourceTree = ""; }; + F15C0DD85D5AB5EE382380DB7D379A41 /* SwiftUI.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftUI.swift; path = RealmSwift/SwiftUI.swift; sourceTree = ""; }; + F1B535C48AA27A28600CB292BA7B62C1 /* RLMObjectId.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMObjectId.mm; path = Realm/RLMObjectId.mm; sourceTree = ""; }; + F313551CDB4FD810DD3CF839F48E5598 /* RLMAPIKeyAuth.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMAPIKeyAuth.h; path = include/RLMAPIKeyAuth.h; sourceTree = ""; }; + F37040080B5A487FC968710228E23835 /* RLMMongoClient.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMMongoClient.mm; path = Realm/RLMMongoClient.mm; sourceTree = ""; }; + F3A2581C1315C787C06C2478DA20B8E7 /* Pods-Bremer-BremerUITests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-Bremer-BremerUITests.modulemap"; sourceTree = ""; }; + F483C66ACB103D856198602AC5ADA1F2 /* realm-monorepo.xcframework */ = {isa = PBXFileReference; includeInIndex = 1; name = "realm-monorepo.xcframework"; path = "core/realm-monorepo.xcframework"; sourceTree = ""; }; + F4FD52B51B2909AAB36AD23B0E5C6F4E /* RLMMigration.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMMigration.mm; path = Realm/RLMMigration.mm; sourceTree = ""; }; + F5AEF06E9131F34D02F83FB90CE4793B /* RealmKeyedCollection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RealmKeyedCollection.swift; path = RealmSwift/RealmKeyedCollection.swift; sourceTree = ""; }; + F6C1A5EFD84B6A50454D576EA03B4DB4 /* RLMArray.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMArray.h; path = include/RLMArray.h; sourceTree = ""; }; + FAC151E989BE61BE27894E9466897C9D /* RLMSyncUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = RLMSyncUtil.mm; path = Realm/RLMSyncUtil.mm; sourceTree = ""; }; + FAEBE82E651C9E62BB79536EA987D7E9 /* Projection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Projection.swift; path = RealmSwift/Projection.swift; sourceTree = ""; }; + FBA363FD1B97BB56E61F71F2AF92764B /* Migration.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Migration.swift; path = RealmSwift/Migration.swift; sourceTree = ""; }; + FCB2F78A679B2F5D906564B85004679B /* ObjectiveCSupport+Sync.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObjectiveCSupport+Sync.swift"; path = "RealmSwift/ObjectiveCSupport+Sync.swift"; sourceTree = ""; }; + FE8350F6C1FADE55F9BF782D08FDABFD /* Realm.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Realm.h; path = include/Realm.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 4B55B4F3E8454CE936EFB8DD56D259F3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 910145FF03824ABFF17CA653C7F0BD5E /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5428928FA2A74A4BB83CFC61438A5D77 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5B6234139BBFD15C7F028858D2C591B8 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AEAB32B0C665670067B5008556E8B00C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D15B7847ABF90E0B55C6EF7C8EDF3158 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DB36D311289F95C8150B8E08452EF298 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E779035800C6FBBF72F017D0C510DF9 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DFB867F47C98FD09EF7F464FAB18623A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A9CCD04E513E9AF636B6D2836A51BAEF /* Foundation.framework in Frameworks */, + 5F878C835ECE9613898BAADD81628269 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 145415CB4FBB13DFBB1E2ED12D501D1B /* Headers */ = { + isa = PBXGroup; + children = ( + 5AF7E94666A9B45384AB13E181E4CD57 /* NSError+RLMSync.h */, + FE8350F6C1FADE55F9BF782D08FDABFD /* Realm.h */, + F313551CDB4FD810DD3CF839F48E5598 /* RLMAPIKeyAuth.h */, + 170BFD8D6212C2BE4613E8915FE93911 /* RLMApp.h */, + F6C1A5EFD84B6A50454D576EA03B4DB4 /* RLMArray.h */, + 15AFE66B86114D491B00DFE510CC6081 /* RLMAsymmetricObject.h */, + 4D53E2B9DA57CF465830EC92CE38FEA7 /* RLMAsyncTask.h */, + 1936DA062F9BE3920D47A14C3DD4851C /* RLMBSON.h */, + 53FEC31B25442C280C915CF78B83081E /* RLMCollection.h */, + 407AB4F6922BDF4346E500A6611B2925 /* RLMConstants.h */, + 8D260A52C53254A6FF21693A13B6D241 /* RLMCredentials.h */, + E5D51CF7CC72E3E01269B1108CD73D9A /* RLMDecimal128.h */, + 308DBDE082D41F22F50C92F0219C0282 /* RLMDictionary.h */, + 3242E2AFF0DE901E8DB25964E6FCA10E /* RLMEmailPasswordAuth.h */, + 1093D1C3E0121F776B90F3F425A05747 /* RLMEmbeddedObject.h */, + DC906F177DFF762E0F2E2A4095889CFE /* RLMError.h */, + 7AB66F45F8EDDFF03F80FCC411B39AAF /* RLMFindOneAndModifyOptions.h */, + E2902657D4B3DF4F908B849A1F5FFD8F /* RLMFindOptions.h */, + 97ACC83057F43D9B6980F6F7C750B9DF /* RLMLogger.h */, + F0CA69915FC0A9DE4556DCAC4009F263 /* RLMMigration.h */, + A6954DA60DEE09E47284DFB14176FC5C /* RLMMongoClient.h */, + 7382B395581C4D5173DD3D9F1FA73E6E /* RLMMongoCollection.h */, + 86C82009901EC92F1F93D8D4E50B2632 /* RLMMongoDatabase.h */, + DD6CF5C22D43D0340212EFD3A0341BE7 /* RLMNetworkTransport.h */, + F123E905A47AB485FEE2C2B6188D39A5 /* RLMObject.h */, + 1AF58B2A8E5F1848F36BD2D6637AC585 /* RLMObjectBase.h */, + 0F6AE9474A96853A8CCEB7217E7882B1 /* RLMObjectBase_Dynamic.h */, + E003BD497C568C08EC768CD231F1AD26 /* RLMObjectId.h */, + D0A8A01C6E0F577E45980964BB353E35 /* RLMObjectSchema.h */, + 156B0F1647DE46158BC285E80693AC3F /* RLMProperty.h */, + A07078F84B897764F4F56E9E30C2AED9 /* RLMProviderClient.h */, + 68B7ABFB3FB23D05DCFCBD5E4F60D8C1 /* RLMPushClient.h */, + 3A122237AC82FC67FCCBBC7B49CF3B6F /* RLMRealm.h */, + 8BF652086B82FCB285AF95A331F06874 /* RLMRealm+Sync.h */, + 14E5074693C241E739C0F88EA9E26D6E /* RLMRealm_Dynamic.h */, + 5048457FAC7400CC15E9FF5E34CC736B /* RLMRealmConfiguration.h */, + E3F27588B6819F964CCE16A4A87A0B84 /* RLMResults.h */, + 44BE1AE28CD9E51D7A284CB0F4570743 /* RLMSchema.h */, + D33AC4A4F700EB53303DA72A42DADD96 /* RLMSectionedResults.h */, + BA42A0E2BDA802CD41C5791B01D95C8A /* RLMSet.h */, + 8096A6CE2B47313736FA293317A1947C /* RLMSwiftCollectionBase.h */, + 251F62CD7F86A4BDC5A5251E2EC9CDE5 /* RLMSwiftObject.h */, + 97803D1FC1CC8551BE103980CD22B5E9 /* RLMSwiftValueStorage.h */, + A9C89270B39D91E8A818E34F32C7799A /* RLMSyncConfiguration.h */, + 0AF05C6D9B63DCA0A6436D62E942292E /* RLMSyncManager.h */, + 3C6F253DE442B7CD2596F4212103F666 /* RLMSyncSession.h */, + 68D58FC196381235BC49DEF871BC6C4E /* RLMSyncSubscription.h */, + 28BDE71E985AC8FBF505AD02C4B30C06 /* RLMThreadSafeReference.h */, + 89578087225F22AF21C2C253BD9F15E7 /* RLMUpdateResult.h */, + 6983861E2027D12D1EE3509BFA276CDC /* RLMUser.h */, + 8503B74C1678228FF9FC0BA42CE15096 /* RLMUserAPIKey.h */, + 656A2602114C6F39008996487E53F025 /* RLMValue.h */, + ); + name = Headers; + sourceTree = ""; + }; + 1628BF05B4CAFDCC3549A101F5A10A17 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 7CE426AC267333500FABE7BA0A5A42A0 /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + 22572B1DED4EA3812D7FDAC1CAC93616 /* RealmSwift */ = { + isa = PBXGroup; + children = ( + 78238DD3B0F804A47333BC5B45487E9C /* Aliases.swift */, + D84BC124274D8FFAD5233B64FF3CAC3E /* AnyRealmValue.swift */, + 9A80C850252DD65379ADE04815FEA92E /* App.swift */, + 7BCF4F4DFBF323D1F496E7AA905F6829 /* AsymmetricObject.swift */, + BC2DDB1B7EB185FFE2B8E387885B7842 /* BasicTypes.swift */, + 71F72372D406C3B51B6B52160127CAFA /* BSON.swift */, + 92DC24CEF1BFE8D67401AA89AE318EAB /* CollectionAccess.swift */, + 1B7374F60D29EB95FE8F0B6E7BC6981C /* Combine.swift */, + 5EC5EE6912182E015407E574294ABDCC /* ComplexTypes.swift */, + 955AB3E9C7A92CB2C66930D1B7A9F8EE /* CustomPersistable.swift */, + C9F7B3C67C23767E4B2FFBC5E3131FA8 /* Decimal128.swift */, + 799DEF74847E011F991ED851F8FB9AD5 /* EmbeddedObject.swift */, + 4F7EFF56DEE55B0043740912E928BE2B /* Error.swift */, + A00386484AF93B1D69A5F465564FF33F /* Events.swift */, + 3FD6D5AC2A4EDD998FDAE19520FB6DA8 /* KeyPathStrings.swift */, + 9049A1739CCEC574D7F368AAF96BC20D /* LinkingObjects.swift */, + DB2B37C3887EC2A789C5465BD724856A /* List.swift */, + CDAF7E43CDAEE6A562D7DE73E48BBD34 /* Map.swift */, + FBA363FD1B97BB56E61F71F2AF92764B /* Migration.swift */, + 79B0FE938D2F799ECCA6EDFA678A1B91 /* MongoClient.swift */, + 47F9EF2D06DD5F0C3364A50CFFD27175 /* MutableSet.swift */, + E57599782133BDF9EB8C7DFCEC56D992 /* ObjcBridgeable.swift */, + B275916C09492961BE9FF64C026D7D5B /* Object.swift */, + ED205C636A7332EDE1203A29F356F902 /* ObjectId.swift */, + E9E53F66B8F189AD9580AE5C05FB1D28 /* ObjectiveCSupport.swift */, + 6B4DD113336EDCBA8E57663DAC98DAED /* ObjectiveCSupport+AnyRealmValue.swift */, + D3A44DB03BC89613444A8677AF8B9718 /* ObjectiveCSupport+BSON.swift */, + FCB2F78A679B2F5D906564B85004679B /* ObjectiveCSupport+Sync.swift */, + 7B3CD4A2BD648DA78AC6D18274B7B3BE /* ObjectSchema.swift */, + 7CCBCA3A7CCA35C254E7412CD7B5C33B /* Optional.swift */, + EFEE93CEA5E067B5DCFE4B87C2F14B73 /* Persistable.swift */, + 8DD5C52ED1637C35CFF24F78FA8E7F34 /* PersistedProperty.swift */, + FAEBE82E651C9E62BB79536EA987D7E9 /* Projection.swift */, + 394000ACEC3525AB18794B5B44ECED44 /* Property.swift */, + 21A3950C70D95063F4AA9D6404705A82 /* PropertyAccessors.swift */, + 42C86ED21C9DEA623DAFDDF386C44A42 /* Query.swift */, + A5C44617F54A134E586D8A6138AEBF85 /* Realm.swift */, + 5B57CFF0C89A929D0188B77FF91CB915 /* RealmCollection.swift */, + E07BC5BBA223584E52693AAB962FD0C1 /* RealmCollectionImpl.swift */, + 8C04C9768E31A75ACAEE02BD5B6CC754 /* RealmConfiguration.swift */, + F5AEF06E9131F34D02F83FB90CE4793B /* RealmKeyedCollection.swift */, + 2DF39689A0A6790771DC1773757C1EAF /* RealmProperty.swift */, + 3E72B23F2A49F29F16A02EFFA295F479 /* Results.swift */, + C9164561687AF22B091FF5B25D0D938A /* RLMSupport.swift */, + 3AE9917146111B7CF81BE6A9EA9097B7 /* Schema.swift */, + EF36B120935792B4001A5634115A5AE9 /* SchemaDiscovery.swift */, + A5CD3E27F8461649EAEFA0D4C6F00E51 /* SectionedResults.swift */, + 02BCC49FB1F90CE18788E9C8DF1F60C9 /* SortDescriptor.swift */, + F15C0DD85D5AB5EE382380DB7D379A41 /* SwiftUI.swift */, + 383925AD60D374AAD8AE07ED633D8731 /* Sync.swift */, + BDBB744BDFC26FF83B92E27D104894BA /* SyncSubscription.swift */, + 67092FC5F8649E5A26AE847AD8A8876D /* ThreadSafeReference.swift */, + 84A6961C92C6C022D5E9CC07787774CC /* Util.swift */, + 90B745421E5A1DA9877429E1C047059A /* Support Files */, + ); + name = RealmSwift; + path = RealmSwift; + sourceTree = ""; + }; + 364694D47BEF3C0B21E187A9089B1D2C /* Pods-BremerTests */ = { + isa = PBXGroup; + children = ( + 56DEB3241033B81B56C42516B00EAF55 /* Pods-BremerTests.modulemap */, + B1FFADEF337AAEECCB0F4A9EB0364182 /* Pods-BremerTests-acknowledgements.markdown */, + 630D71BD599B166A03AF9F122A664074 /* Pods-BremerTests-acknowledgements.plist */, + 54929AAB01C9B10B946F41FBDF583DF4 /* Pods-BremerTests-dummy.m */, + A8F9AABF7EF41FAC511573B7DD1CE8F7 /* Pods-BremerTests-Info.plist */, + 084EDB73408D5ED54E37CC7A8193791C /* Pods-BremerTests-umbrella.h */, + 62714ACEE2FB404ECB36352920522B4B /* Pods-BremerTests.debug.xcconfig */, + 4C8CB92E182DD4E1C1396D71933EFB15 /* Pods-BremerTests.release.xcconfig */, + ); + name = "Pods-BremerTests"; + path = "Target Support Files/Pods-BremerTests"; + sourceTree = ""; + }; + 3C45167986F27C87B421F88512C5486B /* Pods-Bremer-BremerUITests */ = { + isa = PBXGroup; + children = ( + F3A2581C1315C787C06C2478DA20B8E7 /* Pods-Bremer-BremerUITests.modulemap */, + CF895822EEC64C38157631A6BFD04142 /* Pods-Bremer-BremerUITests-acknowledgements.markdown */, + F1112374050461D3B924DCD64699FED3 /* Pods-Bremer-BremerUITests-acknowledgements.plist */, + 1B300F080FDE47388D3EB31854C9C2C8 /* Pods-Bremer-BremerUITests-dummy.m */, + E8B20DE7B2DD404FF067CCBD44C1DF16 /* Pods-Bremer-BremerUITests-frameworks.sh */, + 54D7D00A08CA47ADDD2F30482CD74CA4 /* Pods-Bremer-BremerUITests-Info.plist */, + CF24E6101AE36BCE037294AB302C146B /* Pods-Bremer-BremerUITests-umbrella.h */, + 50C62D1CB8E06C6160D58D4DE83CA25E /* Pods-Bremer-BremerUITests.debug.xcconfig */, + 843867735B0F568A533F9046851F6464 /* Pods-Bremer-BremerUITests.release.xcconfig */, + ); + name = "Pods-Bremer-BremerUITests"; + path = "Target Support Files/Pods-Bremer-BremerUITests"; + sourceTree = ""; + }; + 487F80B2A8C90705D8521706229124CA /* Pods-Bremer */ = { + isa = PBXGroup; + children = ( + 1DC8B026FE1FDFCF15381976F1111E6F /* Pods-Bremer.modulemap */, + 5B3843DC404B5980821B936973765690 /* Pods-Bremer-acknowledgements.markdown */, + 55CA65AB80B992F7E3314562911526F9 /* Pods-Bremer-acknowledgements.plist */, + 7002EA128EE9AD22020152C5C6894C5F /* Pods-Bremer-dummy.m */, + 2F48A095DE75F551D2309337016C13BC /* Pods-Bremer-frameworks.sh */, + CF2A69713E0A59C06190FA785F2973F0 /* Pods-Bremer-Info.plist */, + CB1FDB7543E2546535D25285A7CDCE2C /* Pods-Bremer-umbrella.h */, + 3DF0FA1A97FC74EF390C53A21A64F68A /* Pods-Bremer.debug.xcconfig */, + 6FE040B999F510C22305E6F3F81FDB1E /* Pods-Bremer.release.xcconfig */, + ); + name = "Pods-Bremer"; + path = "Target Support Files/Pods-Bremer"; + sourceTree = ""; + }; + 7CE426AC267333500FABE7BA0A5A42A0 /* iOS */ = { + isa = PBXGroup; + children = ( + 952925E838A0DE4D7BDC4EE54022633D /* Foundation.framework */, + C3B2A0B779CE31153B2C0D8A7F8DC7FE /* Security.framework */, + ); + name = iOS; + sourceTree = ""; + }; + 7F7281FB69EF9BE427D06AEC0C2793C5 /* Pods */ = { + isa = PBXGroup; + children = ( + 884E710FE8E3608F21E6BFA82D46726B /* Realm */, + 22572B1DED4EA3812D7FDAC1CAC93616 /* RealmSwift */, + ); + name = Pods; + sourceTree = ""; + }; + 884E710FE8E3608F21E6BFA82D46726B /* Realm */ = { + isa = PBXGroup; + children = ( + B86B0CF4D89A205EC9854F54BD415F81 /* NSError+RLMSync.m */, + AFBAAA7D9AF1F57EA8E05B3BB9ED1F8D /* RLMAccessor.h */, + BCF15A7FAB1BAB6CF87FA1E1240EAA22 /* RLMAccessor.mm */, + E546E812630FC30731574AD839131FA7 /* RLMAnalytics.mm */, + 12E0802B8D1CD4C7F7B06EB8B6161352 /* RLMAPIKeyAuth.mm */, + 590D63CB0677446E02281D23D4692E4C /* RLMApp.mm */, + 2F6C9E50FB69103202B6E5F4AD647AAB /* RLMApp_Private.h */, + 3E07A833E0493B8D3F6A88C794F249EA /* RLMArray.mm */, + 8B31DC02061BD43612D97809BBE8BF74 /* RLMArray_Private.h */, + 748B44A932F1CC48BB670ED0D3ACC753 /* RLMAsymmetricObject.mm */, + 7BD82FB62C4C6F66BB1E560622D260E1 /* RLMAsyncTask.mm */, + AF06966964C0E0BF8DDBC044F35434E6 /* RLMAsyncTask_Private.h */, + D6125B0B3BCF1040E9B3A78EB5EDF928 /* RLMBSON.mm */, + 0EC784486BA2B84E7CC5BF4FFE73B033 /* RLMClassInfo.mm */, + 4DDAFDDCA2217B2266A2A7953A11B8C8 /* RLMCollection.mm */, + 3EE21D373515813C8D8187A7DB408B8F /* RLMCollection_Private.h */, + 7EBA5CFE49DBE74E402A458118E45875 /* RLMConstants.m */, + 966AE395BC3B71F90831AFE79586D893 /* RLMCredentials.mm */, + B2B3CF7C7D1F83C09082DF1C6AFB0159 /* RLMDecimal128.mm */, + 98406ED6D7929CB5C414D49E3028B995 /* RLMDictionary.mm */, + 72CC1F1C755FBC3CF1BAA38D53EE2BE1 /* RLMDictionary_Private.h */, + DFABC7F89E109F6B72CC258AC4F2DB95 /* RLMEmailPasswordAuth.mm */, + C6CDC4F0BC0FEF0BF1EDAFBE780C3FC0 /* RLMEmbeddedObject.mm */, + 50C117353A5193CCEC27DB1764BCCEE3 /* RLMError.mm */, + 5AA3DBC5397A141FB8A3B336E0C3CA72 /* RLMEvent.h */, + DD5F9555DB50862C43611118F9E6FF20 /* RLMEvent.mm */, + 58E58D6C4EE9BB5E393E64A3A8B042B0 /* RLMFindOneAndModifyOptions.mm */, + DF65E0CB75B86CAF5232510BF6C5994E /* RLMFindOptions.mm */, + 017195EB54DBECB50C413EB1A820E94D /* RLMLogger.mm */, + AEF5520981A82480A9E8725B47C709F1 /* RLMLogger_Private.h */, + 8F40C24E83BF14942C1ECD9977BED25A /* RLMManagedArray.mm */, + CEFA3AA5A6F13EF14DC0485AA3C77E26 /* RLMManagedDictionary.mm */, + 44B69D33543C8F54BB506C2BDA32BCBF /* RLMManagedSet.mm */, + F4FD52B51B2909AAB36AD23B0E5C6F4E /* RLMMigration.mm */, + F37040080B5A487FC968710228E23835 /* RLMMongoClient.mm */, + 36DA7DE9E336E47CEB58E15845B6188C /* RLMMongoCollection.mm */, + 20F8BD3214B20EF37E8F662ACCAAA60C /* RLMMongoCollection_Private.h */, + 1D7A1F605D5891D44CC5D45CB5309EC8 /* RLMNetworkTransport.mm */, + 438EEDFCDE953A0FB47AF574D22EB312 /* RLMObject.mm */, + 156DA493B9D89EC4212074D2C995EF9C /* RLMObject_Private.h */, + B74909372FE229B46DB6568F865259B3 /* RLMObjectBase.mm */, + BF1DA4828D80F3F4FB062A05B6839473 /* RLMObjectBase_Private.h */, + F1B535C48AA27A28600CB292BA7B62C1 /* RLMObjectId.mm */, + 128E2A3A408DD8C462D655821E17014B /* RLMObjectSchema.mm */, + 757457E7DEA8C2AA02BAF76C46377329 /* RLMObjectSchema_Private.h */, + 287A198FE10ED2E080F841D672EEB650 /* RLMObjectStore.h */, + 695219F6ABA376C2FD4EDABC626FA786 /* RLMObjectStore.mm */, + 2B9DEE7FCD724E8946C81F8A781486E9 /* RLMObservation.mm */, + A26ED6EDF207AA276CBAD6DED2156D8E /* RLMPredicateUtil.mm */, + 43C6952CC7740B9F3AFD6D7C5FBB1472 /* RLMProperty.mm */, + 6925048E7FF653A3F7FDA6C80603546F /* RLMProperty_Private.h */, + 7AFFB0657BB0ABFDBE61C1E243296B0A /* RLMProviderClient.mm */, + 23D58A0A4DF4703C125A90D1398E776E /* RLMPushClient.mm */, + 202E9650F11F6AD66598EC94505C0DC0 /* RLMQueryUtil.mm */, + 9CF79020CE57ECA510B1E580B1CE98E5 /* RLMRealm.mm */, + C2FC7E591096B5B21551F74E7DE51CDD /* RLMRealm+Sync.mm */, + 4E1819A1DE7516208F40BA9103184CB9 /* RLMRealm_Private.h */, + A418A33CBA33C7CA3777D174F9A7F6E3 /* RLMRealmConfiguration.mm */, + 99AA99D23861CC51BB876FA7CDEAE774 /* RLMRealmConfiguration_Private.h */, + 1A7E1E1F583157E97280C2C11F60253D /* RLMRealmUtil.mm */, + 98E948B5C4D15AEC19AA92F80B2AFC28 /* RLMResults.mm */, + 5541E31DC0879051FFC3C4EE04F765B9 /* RLMResults_Private.h */, + 8665FB3F64D1560D6687B39D7E65A68F /* RLMScheduler.h */, + D31E3586B5A91CF716C4428503A3CFCD /* RLMScheduler.mm */, + 56900CC788B27223518F048DAECC2413 /* RLMSchema.mm */, + 72BBEB735A09A89265B342D9D00DD130 /* RLMSchema_Private.h */, + C0040FBF8247CDC8C0A0291B31DB2C6E /* RLMSectionedResults.mm */, + 328DA24E2F0FFF97F378C482A57756A6 /* RLMSet.mm */, + CD4D935A3B6C8A82ADB9DF7455DFB90B /* RLMSet_Private.h */, + 4C09B309CFB80885122EC89B6624AA54 /* RLMSwiftCollectionBase.mm */, + 98A99A950E295F01B3CE7F2FBBEBC429 /* RLMSwiftProperty.h */, + 1EB3A9E52A23FB3F9B23BBF63DD7653A /* RLMSwiftSupport.m */, + 3E8354B5E993B479A2BC6DD30FBC6F75 /* RLMSwiftValueStorage.mm */, + 8309845A98031BE7C80BC7899D47FE76 /* RLMSyncConfiguration.mm */, + 31ADBCF4BF2601BDCF3BEB00B234A65A /* RLMSyncConfiguration_Private.h */, + BF970CC730D7528B9F16B94716554C85 /* RLMSyncManager.mm */, + 45E82184D579BFB3425818E1CD186CF1 /* RLMSyncSession.mm */, + 7B9D2B248DEA4041A5D5652F4C370372 /* RLMSyncSubscription.mm */, + 31A8F30D8D7E0AB02362EE0AD1AF1268 /* RLMSyncSubscription_Private.h */, + FAC151E989BE61BE27894E9466897C9D /* RLMSyncUtil.mm */, + 8929353C9A521D1515E318601DB0459F /* RLMThreadSafeReference.mm */, + C0004D5E5EFD0B9DB132A9665F5722ED /* RLMUpdateChecker.mm */, + DF207A2F226C16092CB5DB8515FC4F50 /* RLMUpdateResult.mm */, + 6446CF5660FCF90AA0617D6B16C9B7E2 /* RLMUser.mm */, + 931FFD633662A9674B8F3EF39579EB5C /* RLMUser_Private.h */, + 2D9C769A591C3C701C4B3D66805689FD /* RLMUserAPIKey.mm */, + D3468C0BF4B4320A39D25D9CE6584A26 /* RLMUtil.mm */, + D43F5F1C05A626BF68E6115C5309DE07 /* RLMUUID.mm */, + BE989A32E4CB9545DF1C960611306231 /* RLMValue.mm */, + 8A81D1B81AB6D374B44B0CBC3900D75D /* Frameworks */, + 145415CB4FBB13DFBB1E2ED12D501D1B /* Headers */, + D69078119BF6445091028ED829F1768E /* Support Files */, + ); + name = Realm; + path = Realm; + sourceTree = ""; + }; + 8A81D1B81AB6D374B44B0CBC3900D75D /* Frameworks */ = { + isa = PBXGroup; + children = ( + F483C66ACB103D856198602AC5ADA1F2 /* realm-monorepo.xcframework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 90B745421E5A1DA9877429E1C047059A /* Support Files */ = { + isa = PBXGroup; + children = ( + 5376A112937007DC01BCE9F6BF1A81F0 /* RealmSwift.modulemap */, + 70D19506168EA3B184AB2365D7D7C50D /* RealmSwift-dummy.m */, + C504BA8B8FBFE75AEFA8B3799B0A4184 /* RealmSwift-Info.plist */, + 82C5C50748116066982FC9D2A840A226 /* RealmSwift-prefix.pch */, + 79249BAC9D61B8D7B94CCE8A8E5760C6 /* RealmSwift-umbrella.h */, + 44510D341917737F55D98E6E9746CB05 /* RealmSwift.debug.xcconfig */, + 3420BCC96784716342E7EED0676CA699 /* RealmSwift.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/RealmSwift"; + sourceTree = ""; + }; + A5CF144033F9F8367AB19F8B01852CD1 /* Products */ = { + isa = PBXGroup; + children = ( + 49B40BC6C081C021D6AF3122D256E52C /* Pods-Bremer */, + 3CDDCAA2E3900E5AF247A6EBAED2B0FC /* Pods-Bremer-BremerUITests */, + 53B53BC95B8BCEB3A967BBFB997E527C /* Pods-BremerTests */, + 921BE4A82C4A7A5C72A0C6F8B8FEF200 /* Realm */, + 437919EE08EC6BFCCBAC3BD346309742 /* RealmSwift */, + ); + name = Products; + sourceTree = ""; + }; + CF1408CF629C7361332E53B88F7BD30C = { + isa = PBXGroup; + children = ( + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, + 1628BF05B4CAFDCC3549A101F5A10A17 /* Frameworks */, + 7F7281FB69EF9BE427D06AEC0C2793C5 /* Pods */, + A5CF144033F9F8367AB19F8B01852CD1 /* Products */, + F8779C0DD391E0064057D8A114B1D396 /* Targets Support Files */, + ); + sourceTree = ""; + }; + D69078119BF6445091028ED829F1768E /* Support Files */ = { + isa = PBXGroup; + children = ( + BEB90A9D28C866141E369004C2BAE05D /* Realm.modulemap */, + 5E96A87D4C9F5DE31C5D4A08F2B80B71 /* Realm-dummy.m */, + 0900DCBD41747C1B1D6A5D788E7F4134 /* Realm-Info.plist */, + B6C0D5B885BBC7CEECB041828C3C09E3 /* Realm-prefix.pch */, + 35F8E3BFFB37BB4E8E5F5ABBEE1922B4 /* Realm-xcframeworks.sh */, + 1DC6D46B721373B7304BAA683AF6093A /* Realm.debug.xcconfig */, + 17BF8FF42BA0F44D5871BF66E11034C6 /* Realm.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/Realm"; + sourceTree = ""; + }; + F8779C0DD391E0064057D8A114B1D396 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + 487F80B2A8C90705D8521706229124CA /* Pods-Bremer */, + 3C45167986F27C87B421F88512C5486B /* Pods-Bremer-BremerUITests */, + 364694D47BEF3C0B21E187A9089B1D2C /* Pods-BremerTests */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 2DD9AE2D279C4FB8946404FC77F56799 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CAB172C615714D7B24C3E3CB91C8E73 /* Pods-Bremer-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A581BE0E16E4FCE52E9519A091628842 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 186A9950AD2BC40A5E06896B3F3FFBC4 /* RealmSwift-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BC7E4505DE9CA78871657C40249CD697 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + E366E515D6BD30A71F323FE37BCC1A28 /* Pods-BremerTests-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DB217F37130105F55C6EC35DA678B45E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 99FFBD71C9DDFBB0A14EFDA97F1B02B7 /* Pods-Bremer-BremerUITests-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F748E24BF4ECE4EA9FC6C25CD7114A4D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 9C7A9DE5E81599EB456F1D454F9B9360 /* NSError+RLMSync.h in Headers */, + D9A7B2A7821605D50409B738534A23F6 /* Realm.h in Headers */, + 840529400322C792BCEBF26F90723CA4 /* RLMAccessor.h in Headers */, + 4B914B45266E593F512F835750D69DE3 /* RLMAPIKeyAuth.h in Headers */, + 189009C8E5E5CD765B357ED19A6CEE19 /* RLMApp.h in Headers */, + F0C68CAD88EEDA948E59BB2E89EC3052 /* RLMApp_Private.h in Headers */, + 37EC5BBA3E913B89AFE9B8C24303EE69 /* RLMArray.h in Headers */, + 59D9EED2874474580D0CE585C7DC9EDC /* RLMArray_Private.h in Headers */, + 252CC3FFD233D0E687BBE6928E710F46 /* RLMAsymmetricObject.h in Headers */, + 5E3DFA05C0DBBE379D00AB99AF04296E /* RLMAsyncTask.h in Headers */, + 0B084A2ED53F30E3F5C91705620FC5AB /* RLMAsyncTask_Private.h in Headers */, + 3EEB0BAB4684DBA87988BEBEE5A42AD7 /* RLMBSON.h in Headers */, + 8BD9D141C5B7707226B40ED458DE9A46 /* RLMCollection.h in Headers */, + B6051B422B346D7C2C0C78083AE42593 /* RLMCollection_Private.h in Headers */, + FCA3AA572DB59FC9E2E45FEB3100DAF5 /* RLMConstants.h in Headers */, + 91A36FDEDB3697B2A9CF64A4C1517106 /* RLMCredentials.h in Headers */, + CCC55B25CFC9567D6A2803336B7D1D17 /* RLMDecimal128.h in Headers */, + BEBEEBDD6543109E845B69CC102EF872 /* RLMDictionary.h in Headers */, + 76623954A536129B13F2FFCEE433284C /* RLMDictionary_Private.h in Headers */, + 06358E068A2C99AE81BD71D78017CA21 /* RLMEmailPasswordAuth.h in Headers */, + 3852DA002C2FF5588B5F2626BDCB5085 /* RLMEmbeddedObject.h in Headers */, + 05EC68A60F14F305F3AF79F800F133C3 /* RLMError.h in Headers */, + 04D7A62FC4D8A761493E347FF1788FDF /* RLMEvent.h in Headers */, + 67F8FAC2EA8069948CB07E41CD9A7187 /* RLMFindOneAndModifyOptions.h in Headers */, + A6E6072DF7430D90EA6DC3066FA7F7C7 /* RLMFindOptions.h in Headers */, + 03CFFAB7B53DCDF2AB6C216E304C9846 /* RLMLogger.h in Headers */, + 5EDE608C519C24AF939914110C7CE74B /* RLMLogger_Private.h in Headers */, + 7686BDEA02FB018135B77E758C91C1EB /* RLMMigration.h in Headers */, + 4677B933CB1FAF2518CCEE839EDDD168 /* RLMMongoClient.h in Headers */, + C1FD432E9CBF46B53AEB2152A00DCC91 /* RLMMongoCollection.h in Headers */, + 33F84AB110CBE7AC7E71C170D50E9D10 /* RLMMongoCollection_Private.h in Headers */, + 27C6414300533AB312AEC4C40CDAA341 /* RLMMongoDatabase.h in Headers */, + D0A22FECD9AFFEC60B35A58BEE37A51A /* RLMNetworkTransport.h in Headers */, + 546894780B599D72BE629DE603CE1408 /* RLMObject.h in Headers */, + 8B2072B251574B461AEF7A915C8AF90F /* RLMObject_Private.h in Headers */, + 72C4A427880F50CD06F2246543F5A63E /* RLMObjectBase.h in Headers */, + FE37B576B68AC2671F9ADCB2FDC555C6 /* RLMObjectBase_Dynamic.h in Headers */, + 58B5581101DE8AE5EBFF2FC544D32F0C /* RLMObjectBase_Private.h in Headers */, + 4724AB5CD1E16BBFF664FC2BA7556DBF /* RLMObjectId.h in Headers */, + 189D57C35E8312EF727A1F7F43300B53 /* RLMObjectSchema.h in Headers */, + DFE3D9A4694A51FD0214E86873DA558A /* RLMObjectSchema_Private.h in Headers */, + 02A9BD5CFEF8CF5CDE82D5F3C99595A1 /* RLMObjectStore.h in Headers */, + 33BF9D4F523B37BC98DEFFA47E53D607 /* RLMProperty.h in Headers */, + 0B3B59A97C85AE1077DAA6BBCA438998 /* RLMProperty_Private.h in Headers */, + 5BF823878F8F6A082C28B977CBD89D0F /* RLMProviderClient.h in Headers */, + E899987F3E6214F43909608AE045620A /* RLMPushClient.h in Headers */, + E3DC7B809D4812814D1275565D9A52B7 /* RLMRealm.h in Headers */, + 301E11573A01EEC55F01DD8AF3345675 /* RLMRealm+Sync.h in Headers */, + 47D4A0C3E2AA44B81CA808C6D939E9B3 /* RLMRealm_Dynamic.h in Headers */, + 6C30B5428653570B67A240D491AA0B2C /* RLMRealm_Private.h in Headers */, + 2D451642AC755B81FB7B564B7DA6B871 /* RLMRealmConfiguration.h in Headers */, + BCC16BD326E2270E91F40163F6E39DA1 /* RLMRealmConfiguration_Private.h in Headers */, + 69E7A60C8E32C5FD9D51B19C96529484 /* RLMResults.h in Headers */, + 5B0FE3835069F5DE3B4EE2D3C86CAB0B /* RLMResults_Private.h in Headers */, + 51BA9462B158C88B90D92621AB86DA45 /* RLMScheduler.h in Headers */, + 6F0BD1ED488665BCB5E418BFB949379B /* RLMSchema.h in Headers */, + 92C86DD35BB35AD8C829F7BD677E1BD5 /* RLMSchema_Private.h in Headers */, + DEB4B1192A01C11306500422A677D67D /* RLMSectionedResults.h in Headers */, + 2BF92AC802D5B4E2D986F41990C81C7A /* RLMSet.h in Headers */, + 54A3854C13C2BC05E1F983672735E914 /* RLMSet_Private.h in Headers */, + 0164F3A05EF99C22264D6A0806AB4E6C /* RLMSwiftCollectionBase.h in Headers */, + FF21C29F2325E747CC04BA19B21CF38F /* RLMSwiftObject.h in Headers */, + 3C7C51B018CEE9A67A5C7D5F400A1B21 /* RLMSwiftProperty.h in Headers */, + A34746857C1D93ED5EB769679BE3348B /* RLMSwiftValueStorage.h in Headers */, + 0FBB768B02824170DF603676989A63D2 /* RLMSyncConfiguration.h in Headers */, + A90CBD8E1781E2E19989DD93E5BE8033 /* RLMSyncConfiguration_Private.h in Headers */, + A961A6A4F5DEEEEFD5A03DF58AD26462 /* RLMSyncManager.h in Headers */, + 412DDFCE41F82C3C7947903A74A76034 /* RLMSyncSession.h in Headers */, + 2CA823A0284D819B4E8F7E23A98D0625 /* RLMSyncSubscription.h in Headers */, + E6595B00A83513B21DC169C6319F834F /* RLMSyncSubscription_Private.h in Headers */, + B9B88E7ED730F1F89746B2448FE19D6D /* RLMThreadSafeReference.h in Headers */, + 9C38F4A2700C7A8FA3E01DF077CD7B6D /* RLMUpdateResult.h in Headers */, + 01BD2BEAB90425EBA4BDB2489136B27B /* RLMUser.h in Headers */, + 8BFA582E32D4CCA22809D5D430075BA1 /* RLMUser_Private.h in Headers */, + 732981CA8A49AA1C8CAA06E28CB5009F /* RLMUserAPIKey.h in Headers */, + 287B181CE2842B8EEB1700CCA7CA664E /* RLMValue.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 672DB1E64F5D5FF699632E1AB376B5F1 /* Pods-Bremer-BremerUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 50ED6A6CC03DE6274381BD06BAD9A8E8 /* Build configuration list for PBXNativeTarget "Pods-Bremer-BremerUITests" */; + buildPhases = ( + DB217F37130105F55C6EC35DA678B45E /* Headers */, + EA2745345E22F451356B859C1B434566 /* Sources */, + AEAB32B0C665670067B5008556E8B00C /* Frameworks */, + F329AF85EA19773CB07EB1A0C22B32A4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 318E6DDE3446CB809F253AB53FAEF407 /* PBXTargetDependency */, + BD881B88AD03174F00E5E1ACC1628797 /* PBXTargetDependency */, + ); + name = "Pods-Bremer-BremerUITests"; + productName = Pods_Bremer_BremerUITests; + productReference = 3CDDCAA2E3900E5AF247A6EBAED2B0FC /* Pods-Bremer-BremerUITests */; + productType = "com.apple.product-type.framework"; + }; + 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6DEC7B6193AF0794E21557700EABC0A8 /* Build configuration list for PBXNativeTarget "Realm" */; + buildPhases = ( + F748E24BF4ECE4EA9FC6C25CD7114A4D /* Headers */, + 542F1A369041BB7B845B320F71D685F4 /* Copy . Private Headers */, + 19CAE12F0E356F370555E49572DB2EF2 /* Copy . Public Headers */, + 2A924FCF6012507A217E0DF42370F8BB /* [CP] Copy XCFrameworks */, + 22D23EF88534A5DFF9CF791E97D97024 /* Sources */, + DFB867F47C98FD09EF7F464FAB18623A /* Frameworks */, + 60B8F65E0419050B6E235CB24CA0296C /* Resources */, + 9F41E4BF07CD0C2520045B26BE219B15 /* Create Symlinks to Header Folders */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Realm; + productName = Realm; + productReference = 921BE4A82C4A7A5C72A0C6F8B8FEF200 /* Realm */; + productType = "com.apple.product-type.framework"; + }; + 782725687624F8665247B84AB581BEB1 /* RealmSwift */ = { + isa = PBXNativeTarget; + buildConfigurationList = 47354ADB1930A2E9F4E3E91AAD1FE58A /* Build configuration list for PBXNativeTarget "RealmSwift" */; + buildPhases = ( + A581BE0E16E4FCE52E9519A091628842 /* Headers */, + 7E19C03913F3D1CB2F7603740B976F22 /* Sources */, + 4B55B4F3E8454CE936EFB8DD56D259F3 /* Frameworks */, + BC161F0D64F6CD4690D014D8E20E3BDD /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 0601AECC164DD709717A48897EAA1B2A /* PBXTargetDependency */, + ); + name = RealmSwift; + productName = RealmSwift; + productReference = 437919EE08EC6BFCCBAC3BD346309742 /* RealmSwift */; + productType = "com.apple.product-type.framework"; + }; + 9399214D42B91BBCB8EFD6308884653C /* Pods-Bremer */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7C5E54A8AFE2FF8D1C626B53049A7CAE /* Build configuration list for PBXNativeTarget "Pods-Bremer" */; + buildPhases = ( + 2DD9AE2D279C4FB8946404FC77F56799 /* Headers */, + 6D31112D05B8C347455E0F92E8210D72 /* Sources */, + 5428928FA2A74A4BB83CFC61438A5D77 /* Frameworks */, + 61BD8D1EA3F12588DA4B53984D08757E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 46CF1695D5921A08DF772B26998CA985 /* PBXTargetDependency */, + 870C5EF9242FCA4A9984F5EE20FB9366 /* PBXTargetDependency */, + ); + name = "Pods-Bremer"; + productName = Pods_Bremer; + productReference = 49B40BC6C081C021D6AF3122D256E52C /* Pods-Bremer */; + productType = "com.apple.product-type.framework"; + }; + FE73FF6F368B3C9D9E8AD27094658764 /* Pods-BremerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 14ABD56694B2CDE163EACAE42FEA3EFD /* Build configuration list for PBXNativeTarget "Pods-BremerTests" */; + buildPhases = ( + BC7E4505DE9CA78871657C40249CD697 /* Headers */, + 1DE6C531BE1249B4F030FA5D718786DC /* Sources */, + DB36D311289F95C8150B8E08452EF298 /* Frameworks */, + D7CA27F05D2E7EFA2DE97B56217F6ACA /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 723A1B5F9301BC59FB3AF0512DB1B540 /* PBXTargetDependency */, + ); + name = "Pods-BremerTests"; + productName = Pods_BremerTests; + productReference = 53B53BC95B8BCEB3A967BBFB997E527C /* Pods-BremerTests */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BFDFE7DC352907FC980B868725387E98 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1300; + LastUpgradeCheck = 1300; + }; + buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + Base, + en, + ); + mainGroup = CF1408CF629C7361332E53B88F7BD30C; + productRefGroup = A5CF144033F9F8367AB19F8B01852CD1 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 9399214D42B91BBCB8EFD6308884653C /* Pods-Bremer */, + 672DB1E64F5D5FF699632E1AB376B5F1 /* Pods-Bremer-BremerUITests */, + FE73FF6F368B3C9D9E8AD27094658764 /* Pods-BremerTests */, + 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */, + 782725687624F8665247B84AB581BEB1 /* RealmSwift */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 60B8F65E0419050B6E235CB24CA0296C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 61BD8D1EA3F12588DA4B53984D08757E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BC161F0D64F6CD4690D014D8E20E3BDD /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D7CA27F05D2E7EFA2DE97B56217F6ACA /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F329AF85EA19773CB07EB1A0C22B32A4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 2A924FCF6012507A217E0DF42370F8BB /* [CP] Copy XCFrameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Realm/Realm-xcframeworks-input-files.xcfilelist", + ); + name = "[CP] Copy XCFrameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Realm/Realm-xcframeworks-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Realm/Realm-xcframeworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9F41E4BF07CD0C2520045B26BE219B15 /* Create Symlinks to Header Folders */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Create Symlinks to Header Folders"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "cd \"$CONFIGURATION_BUILD_DIR/$WRAPPER_NAME\" || exit 1\nif [ ! -d Versions ]; then\n # Not a versioned framework, so no need to do anything\n exit 0\nfi\n\npublic_path=\"${PUBLIC_HEADERS_FOLDER_PATH#$CONTENTS_FOLDER_PATH/}\"\nif [ ! -f \"$public_path\" ]; then\n ln -fs \"${PUBLIC_HEADERS_FOLDER_PATH#$WRAPPER_NAME/}\" \"$public_path\"\nfi\n\nprivate_path=\"${PRIVATE_HEADERS_FOLDER_PATH#$CONTENTS_FOLDER_PATH/}\"\nif [ ! -f \"$private_path\" ]; then\n ln -fs \"${PRIVATE_HEADERS_FOLDER_PATH#$WRAPPER_NAME/}\" \"$private_path\"\nfi\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1DE6C531BE1249B4F030FA5D718786DC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D9D541537E0E9CBE619FCB4C5BA41FBC /* Pods-BremerTests-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 22D23EF88534A5DFF9CF791E97D97024 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 373FC80E5CDAC45384582597687CC60E /* NSError+RLMSync.m in Sources */, + 9D1C7542A7BCDEBA0F62F273FD7231B0 /* Realm-dummy.m in Sources */, + E10CC1254774629FBF9FE84379F3AE1F /* RLMAccessor.mm in Sources */, + 20C9EB61BF9B4F9E7313447C3DE77402 /* RLMAnalytics.mm in Sources */, + 8276813797DCDB61494C190FC4E19060 /* RLMAPIKeyAuth.mm in Sources */, + A9AE14432BFCB62033691DD12204CC5A /* RLMApp.mm in Sources */, + F0C6422CF158E3038EF195C6B04B3597 /* RLMArray.mm in Sources */, + B227477A74825C9A83083C0433CBFDD8 /* RLMAsymmetricObject.mm in Sources */, + 958A22AD0045E6D0159B7D4BB3EC46DB /* RLMAsyncTask.mm in Sources */, + 62446C4A47D2141C012B42F3CF874090 /* RLMBSON.mm in Sources */, + CBFF08499AB31E38171D297AF970C55C /* RLMClassInfo.mm in Sources */, + 7454B210CB9C12F734E6CF5781D77750 /* RLMCollection.mm in Sources */, + C49A30D54C6C024842C726A7A0A349C3 /* RLMConstants.m in Sources */, + E7FE0FE9CCC81F971080577E75A9BADF /* RLMCredentials.mm in Sources */, + DC846F05C78BFE7388A9FCC22D6855C0 /* RLMDecimal128.mm in Sources */, + D6725A83F0BDF7F1CD1EFD5DB116CE0A /* RLMDictionary.mm in Sources */, + 5D0027837717618EAE09864D9728EB35 /* RLMEmailPasswordAuth.mm in Sources */, + 87A5DD69BBFC72B10DCE234AD915AECA /* RLMEmbeddedObject.mm in Sources */, + 856241060FCD8F54D41C8100D5467EA1 /* RLMError.mm in Sources */, + BAD6F720447F880C4E8C293236558AA2 /* RLMEvent.mm in Sources */, + 7190FAB0A2288A73BB2C10D69492068D /* RLMFindOneAndModifyOptions.mm in Sources */, + 69130970F3EA2B79379ACCAC115A7326 /* RLMFindOptions.mm in Sources */, + DD5565CB03976C136614929A24AFEB00 /* RLMLogger.mm in Sources */, + 0593AF2DD216BD5C78A89C94561EB0BD /* RLMManagedArray.mm in Sources */, + 53A11D4781B500C01BD4B7E2D3E5CD3A /* RLMManagedDictionary.mm in Sources */, + 66BD8017F7819384898E59C08F01482F /* RLMManagedSet.mm in Sources */, + 3D92323EDE4D29026A9374B64C97F9AE /* RLMMigration.mm in Sources */, + 2B2C5BD99F284AB4318D76E496B08D20 /* RLMMongoClient.mm in Sources */, + D557744183CF5535DECED314499DDE07 /* RLMMongoCollection.mm in Sources */, + B2A59ED57987B4C045C2E426CA784F3C /* RLMNetworkTransport.mm in Sources */, + E7E8EB6C98BEBF86A61A10162B9D53DB /* RLMObject.mm in Sources */, + 071AAAAA27F2BFD0E44D86939213CC91 /* RLMObjectBase.mm in Sources */, + 97BF699AC80B0A8F6D3A89EBE06C699E /* RLMObjectId.mm in Sources */, + 69E27BAAB5EE0731092AD1B2301D58A1 /* RLMObjectSchema.mm in Sources */, + 13281771BE43BAF65031D19E8CCFC5FB /* RLMObjectStore.mm in Sources */, + 34824E3B12CFBDA9EAA9843EFB15B521 /* RLMObservation.mm in Sources */, + 4AC5B90C5F737677057D17D51A2581C0 /* RLMPredicateUtil.mm in Sources */, + 6D311C71E3835300ED0B39A347395894 /* RLMProperty.mm in Sources */, + E67507D98B3AFB1C33E80C4999086D23 /* RLMProviderClient.mm in Sources */, + 8E4946AF47D0CB535546BCCC8EFA5ED3 /* RLMPushClient.mm in Sources */, + A30CECDE48E690E4C81DFAACB9D48A3C /* RLMQueryUtil.mm in Sources */, + D82B59171BB4C4C7158759A41E6FECF6 /* RLMRealm.mm in Sources */, + AB60957A130323D5FACF4F2991B70391 /* RLMRealm+Sync.mm in Sources */, + 6C523F77EC93669F5110AD340DD7FA4C /* RLMRealmConfiguration.mm in Sources */, + 8A3E3F36EEEE830D273FB455144921CF /* RLMRealmUtil.mm in Sources */, + 6B417758244574B7B3C30ACED4931D87 /* RLMResults.mm in Sources */, + 6BB65F955B515386823B4E2489460EC2 /* RLMScheduler.mm in Sources */, + 5BF421BE48A7F2C14D62429966DF9CC3 /* RLMSchema.mm in Sources */, + C34D354EFB0278C45DFBF4DA47DEBF74 /* RLMSectionedResults.mm in Sources */, + CBFF56BD941E3BAE6D8A1A7CCBB4F207 /* RLMSet.mm in Sources */, + 148B5987885C44A9CCA6440E526AB8DB /* RLMSwiftCollectionBase.mm in Sources */, + BC3767360C4E6C8373B927EEEFF2310D /* RLMSwiftSupport.m in Sources */, + 2D8AC0448C53894AED8E92735A536CD6 /* RLMSwiftValueStorage.mm in Sources */, + 3083EA5E1DB8A69E5D4AA5C14044E6E6 /* RLMSyncConfiguration.mm in Sources */, + 2949EF413D29DD8D9B589CF18B207330 /* RLMSyncManager.mm in Sources */, + 30F9BAC69B2C307C45EEA6EF45302FBC /* RLMSyncSession.mm in Sources */, + 511C4C72919EA280FE5A26BA62C87F3A /* RLMSyncSubscription.mm in Sources */, + D40B4ABC458054D8C3E5D10377A2CEE0 /* RLMSyncUtil.mm in Sources */, + 66B68F7A52CB423990C5E3ED589FC9F9 /* RLMThreadSafeReference.mm in Sources */, + FFC5AD5D9C84E7800EB949BFC5E51EE0 /* RLMUpdateChecker.mm in Sources */, + 0A6750B00EA3B3674F044F5FDF5D5AD5 /* RLMUpdateResult.mm in Sources */, + 03FF5CF0BBF8F4C1C997DAA2C73495AF /* RLMUser.mm in Sources */, + 6C49271A9472DCAA4D047D65D9B0FEC2 /* RLMUserAPIKey.mm in Sources */, + 18FA4829DF1DB108BF59C6BFA8DBB690 /* RLMUtil.mm in Sources */, + 820BF0662635667610DD218CFAC68030 /* RLMUUID.mm in Sources */, + 363350BF63DCB3B5C76A241D02D672FD /* RLMValue.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6D31112D05B8C347455E0F92E8210D72 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C50B84D7B7EEB94A97C13C8AD3F7E23D /* Pods-Bremer-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7E19C03913F3D1CB2F7603740B976F22 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 39EA99A31B37C65E005202F18FBB2782 /* Aliases.swift in Sources */, + 2E9DCF5DE252DD97076AFC91842225CF /* AnyRealmValue.swift in Sources */, + 682649CEC1CA3CFF6F01C692754E53D5 /* App.swift in Sources */, + B785E35AE212C2CB4C4CD0D84C49B90D /* AsymmetricObject.swift in Sources */, + BF5352E6A21E27DB879C2189155F17EA /* BasicTypes.swift in Sources */, + 3F5DC8E1E4127053A92C72E08D27F5D8 /* BSON.swift in Sources */, + DE9AC4D1B35C9E07B979930D5C0B38DF /* CollectionAccess.swift in Sources */, + B59E22971F8D4CE5681BF67535A363F7 /* Combine.swift in Sources */, + 8A9025AE4A9232EF04AAFFA2EEA1416F /* ComplexTypes.swift in Sources */, + 3E036CAA97F279B0C6ABD859726A047A /* CustomPersistable.swift in Sources */, + 5B8A458DC7C87F427A5C463F3CAC517B /* Decimal128.swift in Sources */, + 7AA5D2ED28C6B278DB39BC615D38ED5B /* EmbeddedObject.swift in Sources */, + FE7FC652161CB9CBDDBA9E5BE3397011 /* Error.swift in Sources */, + 8BD86B5E5C4D9040FF6F940A7DDE5B5E /* Events.swift in Sources */, + 0442CEDEA4243DD8629F664272A285DE /* KeyPathStrings.swift in Sources */, + 1CA0567A035870C832DE6060E1C348A1 /* LinkingObjects.swift in Sources */, + DC1CC94EA95338783CD4596CF2882942 /* List.swift in Sources */, + 781671C9525101E2C5AC80A6C3DF54C6 /* Map.swift in Sources */, + 752C7184ED4531729174293BFC7AF6E7 /* Migration.swift in Sources */, + ABD61BF538B0440B014502E121AD906D /* MongoClient.swift in Sources */, + B837F9BAA1E321E18780F3B8903BC004 /* MutableSet.swift in Sources */, + D9D8EA266CD7C5885464952BC9B2678D /* ObjcBridgeable.swift in Sources */, + F3117B7CBCA74424D090B0911C96DC89 /* Object.swift in Sources */, + C11339074CE5C4A8DF75384CCC987B77 /* ObjectId.swift in Sources */, + 2C7492344C6598F8514582D5B34F6956 /* ObjectiveCSupport.swift in Sources */, + BBCE391F1AC55EFC2A589E550ACCC1B6 /* ObjectiveCSupport+AnyRealmValue.swift in Sources */, + 868EC2D6F5E462D6EC55BCAA99DA1848 /* ObjectiveCSupport+BSON.swift in Sources */, + 5F0A29426B5289CE22EE51AFE0A28775 /* ObjectiveCSupport+Sync.swift in Sources */, + F80CCCEBF9794DC3E8B4EEB8FAAA2D0B /* ObjectSchema.swift in Sources */, + AAD9FDCF7389C0EFE67CCD5B9BAF3115 /* Optional.swift in Sources */, + 13B5FCEFE1051075D694B06BD6345BB2 /* Persistable.swift in Sources */, + AFFEB160C9DAC32478B61FCCED14535B /* PersistedProperty.swift in Sources */, + 5A112F8271072DE73024CBA8078043AA /* Projection.swift in Sources */, + 609EB115EBE2C1BB25EE2FF2EE67A4BD /* Property.swift in Sources */, + 6FC16F5639926D99A63C51C6AB855C2D /* PropertyAccessors.swift in Sources */, + 07F261922769AA1165299B51787D22D6 /* Query.swift in Sources */, + A2D241953E4F2DA88EEC3CED7DEDF8B1 /* Realm.swift in Sources */, + B4EE276AF7CB12ED9DB48318D8914C2B /* RealmCollection.swift in Sources */, + 1E563604E3C43CD98D2CFC150359E536 /* RealmCollectionImpl.swift in Sources */, + 1059F6E4C81D4442F9A0443E56682D22 /* RealmConfiguration.swift in Sources */, + FE2F13D80F1F4B8A605390C3399EF3AD /* RealmKeyedCollection.swift in Sources */, + B46E52EDBD14DEA140A5EE7F128F7D70 /* RealmProperty.swift in Sources */, + 56040CFFA72105E3B95C1D44A8AAD299 /* RealmSwift-dummy.m in Sources */, + 06304E80795DA749417F68A31C6A4D74 /* Results.swift in Sources */, + 58C96277ECC03358ED0A472DA23F3F53 /* RLMSupport.swift in Sources */, + 8C42A7A9022BBAFCF982F250E3A7500D /* Schema.swift in Sources */, + 71ED8B725658B0D3E35D4B72106BC615 /* SchemaDiscovery.swift in Sources */, + 79DF5164542097A87970D857C22688FD /* SectionedResults.swift in Sources */, + 1AE31850261F971BBAE81FA9859C5DBE /* SortDescriptor.swift in Sources */, + 876EE37947934409808939990FBC28D7 /* SwiftUI.swift in Sources */, + 3E1B5386B32268FA87A5B13C81242612 /* Sync.swift in Sources */, + 3EEB5CD0432AE4C966A336FE407F4564 /* SyncSubscription.swift in Sources */, + CCD1C585CE4E9DBE15769F38E06842C2 /* ThreadSafeReference.swift in Sources */, + E34B80A9A8B49857FCD043CAE44D1EC0 /* Util.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EA2745345E22F451356B859C1B434566 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 17A47338450241D6C0BCD42C9B9FDFF0 /* Pods-Bremer-BremerUITests-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 0601AECC164DD709717A48897EAA1B2A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Realm; + target = 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */; + targetProxy = FC2F95BCBA2B20A264CB04B37382F5B9 /* PBXContainerItemProxy */; + }; + 318E6DDE3446CB809F253AB53FAEF407 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Realm; + target = 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */; + targetProxy = AA0E21EBF22F66387EFA4044F9352A74 /* PBXContainerItemProxy */; + }; + 46CF1695D5921A08DF772B26998CA985 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Realm; + target = 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */; + targetProxy = A294B51E81F4F9714F641F956BCDFDD4 /* PBXContainerItemProxy */; + }; + 723A1B5F9301BC59FB3AF0512DB1B540 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Pods-Bremer"; + target = 9399214D42B91BBCB8EFD6308884653C /* Pods-Bremer */; + targetProxy = 6E62B7B55E80A98A7C3B305B2D5767E5 /* PBXContainerItemProxy */; + }; + 870C5EF9242FCA4A9984F5EE20FB9366 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RealmSwift; + target = 782725687624F8665247B84AB581BEB1 /* RealmSwift */; + targetProxy = D6A4888DF0287DD834BE6DAF07C350C7 /* PBXContainerItemProxy */; + }; + BD881B88AD03174F00E5E1ACC1628797 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RealmSwift; + target = 782725687624F8665247B84AB581BEB1 /* RealmSwift */; + targetProxy = CB828421E54C4F9E9403280D1039F501 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 103C775A12EF4A73FE3DCB70BB9C912B /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1DC6D46B721373B7304BAA683AF6093A /* Realm.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/Realm/Realm-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Realm/Realm-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/Realm/Realm.modulemap"; + PRODUCT_MODULE_NAME = Realm; + PRODUCT_NAME = Realm; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 30E0B9EFD9A5C45D0D351231E81B30B3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Release; + }; + 47E4CBF639D6C513F05BC7FD1349A2C3 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 17BF8FF42BA0F44D5871BF66E11034C6 /* Realm.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/Realm/Realm-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Realm/Realm-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/Realm/Realm.modulemap"; + PRODUCT_MODULE_NAME = Realm; + PRODUCT_NAME = Realm; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 6882E7997D8CEC41D3A635A1F7B71CDB /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 843867735B0F568A533F9046851F6464 /* Pods-Bremer-BremerUITests.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-Bremer-BremerUITests/Pods-Bremer-BremerUITests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Bremer-BremerUITests/Pods-Bremer-BremerUITests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 6E8F94691B9F8AC9E8022C16E716F4E8 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 62714ACEE2FB404ECB36352920522B4B /* Pods-BremerTests.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-BremerTests/Pods-BremerTests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-BremerTests/Pods-BremerTests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 7F8F29131901D2436365A63F4A7C7C50 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6FE040B999F510C22305E6F3F81FDB1E /* Pods-Bremer.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-Bremer/Pods-Bremer-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Bremer/Pods-Bremer.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 84971A590416E7195FA3E895F88755D0 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3420BCC96784716342E7EED0676CA699 /* RealmSwift.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RealmSwift/RealmSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RealmSwift/RealmSwift-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/RealmSwift/RealmSwift.modulemap"; + PRODUCT_MODULE_NAME = RealmSwift; + PRODUCT_NAME = RealmSwift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 9DD0C2A9A5A8060C34E72DB9DAC37FFE /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3DF0FA1A97FC74EF390C53A21A64F68A /* Pods-Bremer.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-Bremer/Pods-Bremer-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Bremer/Pods-Bremer.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + AD67ACEC5E0CB491BF2C49D02AC8064D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 44510D341917737F55D98E6E9746CB05 /* RealmSwift.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RealmSwift/RealmSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RealmSwift/RealmSwift-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/RealmSwift/RealmSwift.modulemap"; + PRODUCT_MODULE_NAME = RealmSwift; + PRODUCT_NAME = RealmSwift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + AE234BD943297BEE627B6A26B7997AE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 4C8CB92E182DD4E1C1396D71933EFB15 /* Pods-BremerTests.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-BremerTests/Pods-BremerTests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-BremerTests/Pods-BremerTests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + C6835E2D468B0730407193805F9DB88F /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 50C62D1CB8E06C6160D58D4DE83CA25E /* Pods-Bremer-BremerUITests.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-Bremer-BremerUITests/Pods-Bremer-BremerUITests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Bremer-BremerUITests/Pods-Bremer-BremerUITests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + F4FF6A0D1970CA9705974E3CB2134802 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 14ABD56694B2CDE163EACAE42FEA3EFD /* Build configuration list for PBXNativeTarget "Pods-BremerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6E8F94691B9F8AC9E8022C16E716F4E8 /* Debug */, + AE234BD943297BEE627B6A26B7997AE5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 47354ADB1930A2E9F4E3E91AAD1FE58A /* Build configuration list for PBXNativeTarget "RealmSwift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AD67ACEC5E0CB491BF2C49D02AC8064D /* Debug */, + 84971A590416E7195FA3E895F88755D0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F4FF6A0D1970CA9705974E3CB2134802 /* Debug */, + 30E0B9EFD9A5C45D0D351231E81B30B3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 50ED6A6CC03DE6274381BD06BAD9A8E8 /* Build configuration list for PBXNativeTarget "Pods-Bremer-BremerUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C6835E2D468B0730407193805F9DB88F /* Debug */, + 6882E7997D8CEC41D3A635A1F7B71CDB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6DEC7B6193AF0794E21557700EABC0A8 /* Build configuration list for PBXNativeTarget "Realm" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 103C775A12EF4A73FE3DCB70BB9C912B /* Debug */, + 47E4CBF639D6C513F05BC7FD1349A2C3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7C5E54A8AFE2FF8D1C626B53049A7CAE /* Build configuration list for PBXNativeTarget "Pods-Bremer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9DD0C2A9A5A8060C34E72DB9DAC37FFE /* Debug */, + 7F8F29131901D2436365A63F4A7C7C50 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */; +} diff --git a/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/Pods-Bremer-BremerUITests.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/Pods-Bremer-BremerUITests.xcscheme new file mode 100644 index 0000000..fbd72ba --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/Pods-Bremer-BremerUITests.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/Pods-Bremer.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/Pods-Bremer.xcscheme new file mode 100644 index 0000000..f894d0f --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/Pods-Bremer.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/Pods-BremerTests.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/Pods-BremerTests.xcscheme new file mode 100644 index 0000000..8a8eb41 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/Pods-BremerTests.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/Realm.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/Realm.xcscheme new file mode 100644 index 0000000..628de49 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/Realm.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/RealmSwift.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/RealmSwift.xcscheme new file mode 100644 index 0000000..2bdb5cd --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/RealmSwift.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/xcschememanagement.plist b/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..4798624 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/alisha.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,46 @@ + + + + + SchemeUserState + + Pods-Bremer-BremerUITests.xcscheme + + isShown + + orderHint + 1 + + Pods-Bremer.xcscheme + + isShown + + orderHint + 0 + + Pods-BremerTests.xcscheme + + isShown + + orderHint + 2 + + Realm.xcscheme + + isShown + + orderHint + 3 + + RealmSwift.xcscheme + + isShown + + orderHint + 4 + + + SuppressBuildableAutocreation + + + diff --git a/Pods/Realm/LICENSE b/Pods/Realm/LICENSE new file mode 100644 index 0000000..66a27ec --- /dev/null +++ b/Pods/Realm/LICENSE @@ -0,0 +1,177 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/Pods/Realm/README.md b/Pods/Realm/README.md new file mode 100644 index 0000000..3297a19 --- /dev/null +++ b/Pods/Realm/README.md @@ -0,0 +1,175 @@ +![Realm](https://github.com/realm/realm-swift/raw/master/logo.png) + +# About Realm Database + +Realm is a mobile database that runs directly inside phones, tablets or wearables. +This repository holds the source code for the iOS, macOS, tvOS & watchOS versions of Realm Swift & Realm Objective-C. + +## Why Use Realm + +* **Intuitive to Developers:** Realm’s object-oriented data model is simple to learn, doesn’t need an ORM, and lets you write less code. +* **Built for Mobile:** Realm is fully-featured, lightweight, and efficiently uses memory, disk space, and battery life. +* **Designed for Offline Use:** Realm’s local database persists data on-disk, so apps work as well offline as they do online. +* **[Device Sync](https://www.mongodb.com/atlas/app-services/device-sync)**: Makes it simple to keep data in sync across users, devices, and your backend in real-time. Get started for free with [a template application](https://github.com/mongodb/template-app-swiftui-todo) and [create the cloud backend](http://mongodb.com/realm/register?utm_medium=github_atlas_CTA&utm_source=realm_swift_github). + +## Object-Oriented: Streamline Your Code + +Realm was built for mobile developers, with simplicity in mind. The idiomatic, object-oriented data model can save you thousands of lines of code. + +```swift +// Define your models like regular Swift classes +class Dog: Object { + @Persisted var name: String + @Persisted var age: Int +} +class Person: Object { + @Persisted(primaryKey: true) var _id: String + @Persisted var name: String + @Persisted var age: Int + // Create relationships by pointing an Object field to another Class + @Persisted var dogs: List +} +// Use them like regular Swift objects +let dog = Dog() +dog.name = "Rex" +dog.age = 1 +print("name of dog: \(dog.name)") + +// Get the default Realm +let realm = try! Realm() +// Persist your data easily with a write transaction +try! realm.write { + realm.add(dog) +} +``` +## Live Objects: Build Reactive Apps +Realm’s live objects mean data updated anywhere is automatically updated everywhere. +```swift +// Open the default realm. +let realm = try! Realm() + +var token: NotificationToken? + +let dog = Dog() +dog.name = "Max" + +// Create a dog in the realm. +try! realm.write { + realm.add(dog) +} + +// Set up the listener & observe object notifications. +token = dog.observe { change in + switch change { + case .change(let properties): + for property in properties { + print("Property '\(property.name)' changed to '\(property.newValue!)'"); + } + case .error(let error): + print("An error occurred: (error)") + case .deleted: + print("The object was deleted.") + } +} + +// Update the dog's name to see the effect. +try! realm.write { + dog.name = "Wolfie" +} +``` +### SwiftUI +Realm integrates directly with SwiftUI, updating your views so you don't have to. +```swift +struct ContactsView: View { + @ObservedResults(Person.self) var persons + + var body: some View { + List { + ForEach(persons) { person in + Text(person.name) + } + .onMove(perform: $persons.move) + .onDelete(perform: $persons.remove) + }.navigationBarItems(trailing: + Button("Add") { + $persons.append(Person()) + } + ) + } +} +``` + +## Fully Encrypted +Data can be encrypted in-flight and at-rest, keeping even the most sensitive data secure. +```swift +// Generate a random encryption key +var key = Data(count: 64) +_ = key.withUnsafeMutableBytes { bytes in + SecRandomCopyBytes(kSecRandomDefault, 64, bytes) +} + +// Add the encryption key to the config and open the realm +let config = Realm.Configuration(encryptionKey: key) +let realm = try Realm(configuration: config) + +// Use the Realm as normal +let dogs = realm.objects(Dog.self).filter("name contains 'Fido'") +``` + +## Getting Started + +We support installing Realm via Swift Package Manager, CocoaPods, Carthage, or by importing a dynamic XCFramework. + +For more information, see the detailed instructions in our [docs](https://docs.mongodb.com/realm/sdk/ios/install/). + +Interested in getting started for free with [a template application](https://github.com/mongodb/template-app-swiftui-todo) that includes a cloud backend and Sync? [Create a MongoDB Atlas Account](http://mongodb.com/realm/register?utm_medium=github_atlas_CTA&utm_source=realm_swift_github). + +## Documentation + +The documentation can be found at [docs.mongodb.com/realm/sdk/ios/](https://docs.mongodb.com/realm/sdk/ios/). +The API reference is located at [docs.mongodb.com/realm-sdks/swift/latest/](https://docs.mongodb.com/realm-sdks/swift/latest/) + +## Getting Help + +- **Need help with your code?**: Look for previous questions with the[`realm` tag](https://stackoverflow.com/questions/tagged/realm?sort=newest) on Stack Overflow or [ask a new question](https://stackoverflow.com/questions/ask?tags=realm). For general discussion that might be considered too broad for Stack Overflow, use the [Community Forum](https://developer.mongodb.com/community/forums/tags/c/realm-sdks/58/swift/). +- **Have a bug to report?** [Open a GitHub issue](https://github.com/realm/realm-swift/issues/new). If possible, include the version of Realm, a full log, the Realm file, and a project that shows the issue. +- **Have a feature request?** [Open a GitHub issue](https://github.com/realm/realm-swift/issues/new). Tell us what the feature should do and why you want the feature. + +## Building Realm + +In case you don't want to use the precompiled version, you can build Realm yourself from source. + +Prerequisites: + +* Building Realm requires Xcode 14.1 or newer. +* Building Realm documentation requires [jazzy](https://github.com/realm/jazzy) + +Once you have all the necessary prerequisites, building Realm just takes a single command: `sh build.sh build`. +You'll need an internet connection the first time you build Realm to download the core binary. +This will produce Realm.xcframework and RealmSwift.xcframework in `build/Release/`. + +Run `sh build.sh help` to see all the actions you can perform (build ios/osx, generate docs, test, etc.). + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) for more details! + +## Code of Conduct + +This project adheres to the [MongoDB Code of Conduct](https://www.mongodb.com/community-code-of-conduct). +By participating, you are expected to uphold this code. Please report +unacceptable behavior to [community-conduct@mongodb.com](mailto:community-conduct@mongodb.com). + +## License + +Realm Objective-C & Realm Swift are published under the Apache 2.0 license. +Realm Core is also published under the Apache 2.0 license and is available +[here](https://github.com/realm/realm-core). + +## Feedback + +**_If you use Realm and are happy with it, please consider sending out a tweet mentioning [@realm](https://twitter.com/realm) to share your thoughts!_** + +**_And if you don't like it, please let us know what you would like improved, so we can fix it!_** + + diff --git a/Pods/Realm/Realm/NSError+RLMSync.m b/Pods/Realm/Realm/NSError+RLMSync.m new file mode 100644 index 0000000..4825c01 --- /dev/null +++ b/Pods/Realm/Realm/NSError+RLMSync.m @@ -0,0 +1,43 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2017 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "NSError+RLMSync.h" + +#import "RLMError.h" + +@implementation NSError (RLMSync) + +- (RLMSyncErrorActionToken *)rlmSync_errorActionToken { + if (self.domain != RLMSyncErrorDomain) { + return nil; + } + if (self.code == RLMSyncErrorClientResetError + || self.code == RLMSyncErrorPermissionDeniedError) { + return (RLMSyncErrorActionToken *)self.userInfo[kRLMSyncErrorActionTokenKey]; + } + return nil; +} + +- (NSString *)rlmSync_clientResetBackedUpRealmPath { + if (self.domain == RLMSyncErrorDomain && self.code == RLMSyncErrorClientResetError) { + return self.userInfo[kRLMSyncPathOfRealmBackupCopyKey]; + } + return nil; +} + +@end diff --git a/Pods/Realm/Realm/RLMAPIKeyAuth.mm b/Pods/Realm/Realm/RLMAPIKeyAuth.mm new file mode 100644 index 0000000..ded32cc --- /dev/null +++ b/Pods/Realm/Realm/RLMAPIKeyAuth.mm @@ -0,0 +1,90 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMAPIKeyAuth.h" +#import "RLMProviderClient_Private.hpp" + +#import "RLMApp_Private.hpp" +#import "RLMUserAPIKey_Private.hpp" +#import "RLMObjectId_Private.hpp" + +using namespace realm::app; + +@implementation RLMAPIKeyAuth + +- (App::UserAPIKeyProviderClient)client { + return self.app._realmApp->provider_client(); +} + +- (std::shared_ptr)currentUser { + return self.app._realmApp->current_user(); +} + +static realm::util::UniqueFunction)> +wrapCompletion(RLMOptionalUserAPIKeyBlock completion) { + return [completion](App::UserAPIKey userAPIKey, std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + return completion([[RLMUserAPIKey alloc] initWithUserAPIKey:userAPIKey], nil); + }; +} + +- (void)createAPIKeyWithName:(NSString *)name + completion:(RLMOptionalUserAPIKeyBlock)completion { + self.client.create_api_key(name.UTF8String, self.currentUser, wrapCompletion(completion)); +} + +- (void)fetchAPIKey:(RLMObjectId *)objectId + completion:(RLMOptionalUserAPIKeyBlock)completion { + self.client.fetch_api_key(objectId.value, self.currentUser, wrapCompletion(completion)); +} + +- (void)fetchAPIKeysWithCompletion:(RLMUserAPIKeysBlock)completion { + self.client.fetch_api_keys(self.currentUser, + ^(const std::vector& userAPIKeys, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + + NSMutableArray *apiKeys = [[NSMutableArray alloc] init]; + for (auto &userAPIKey : userAPIKeys) { + [apiKeys addObject:[[RLMUserAPIKey alloc] initWithUserAPIKey:userAPIKey]]; + } + + return completion(apiKeys, nil); + }); +} + +- (void)deleteAPIKey:(RLMObjectId *)objectId + completion:(RLMAPIKeyAuthOptionalErrorBlock)completion { + self.client.delete_api_key(objectId.value, self.currentUser, RLMWrapCompletion(completion)); +} + +- (void)enableAPIKey:(RLMObjectId *)objectId + completion:(RLMAPIKeyAuthOptionalErrorBlock)completion { + self.client.enable_api_key(objectId.value, self.currentUser, RLMWrapCompletion(completion)); +} + +- (void)disableAPIKey:(RLMObjectId *)objectId + completion:(RLMAPIKeyAuthOptionalErrorBlock)completion { + self.client.disable_api_key(objectId.value, self.currentUser, RLMWrapCompletion(completion)); +} + +@end diff --git a/Pods/Realm/Realm/RLMAccessor.mm b/Pods/Realm/Realm/RLMAccessor.mm new file mode 100644 index 0000000..db75987 --- /dev/null +++ b/Pods/Realm/Realm/RLMAccessor.mm @@ -0,0 +1,1197 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMAccessor.hpp" + +#import "RLMArray_Private.hpp" +#import "RLMDictionary_Private.hpp" +#import "RLMObjectId_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMRealm_Private.hpp" +#import "RLMResults_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftProperty.h" +#import "RLMUUID_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import + +#import +#import + +#pragma mark Helper functions + +using realm::ColKey; + +namespace realm { +template<> +Obj Obj::get(ColKey col) const { + ObjKey key = get(col); + return key ? get_target_table(col)->get_object(key) : Obj(); +} + +} // namespace realm + +namespace { +realm::Property const& getProperty(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index) { + return obj->_info->objectSchema->persisted_properties[index]; +} + +realm::Property const& getProperty(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained RLMProperty *const prop) { + if (prop.linkOriginPropertyName) { + return obj->_info->objectSchema->computed_properties[prop.index]; + } + return obj->_info->objectSchema->persisted_properties[prop.index]; +} + +template +bool isNull(T const& v) { + return !v; +} +template<> +bool isNull(realm::Timestamp const& v) { + return v.is_null(); +} +template<> +bool isNull(realm::ObjectId const&) { + return false; +} +template<> +bool isNull(realm::Decimal128 const& v) { + return v.is_null(); +} +template<> +bool isNull(realm::Mixed const& v) { + return v.is_null(); +} +template<> +bool isNull(realm::UUID const&) { + return false; +} + +template +T get(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index) { + RLMVerifyAttached(obj); + return obj->_row.get(getProperty(obj, index).column_key); +} + +template +id getBoxed(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index) { + RLMVerifyAttached(obj); + auto& prop = getProperty(obj, index); + RLMAccessorContext ctx(obj, &prop); + auto value = obj->_row.get(prop.column_key); + return isNull(value) ? nil : ctx.box(std::move(value)); +} + +template +T getOptional(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, bool *gotValue) { + auto ret = get>(obj, key); + if (ret) { + *gotValue = true; + } + return ret.value_or(T{}); +} + +template +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, T val) { + obj->_row.set(key, val); +} + +template +void setValueOrNull(__unsafe_unretained RLMObjectBase *const obj, ColKey col, + __unsafe_unretained id const value) { + RLMVerifyInWriteTransaction(obj); + + RLMTranslateError([&] { + if (value) { + if constexpr (std::is_same_v) { + obj->_row.set(col, RLMObjcToMixed(value, obj->_realm, realm::CreatePolicy::SetLink)); + } + else { + RLMStatelessAccessorContext ctx; + obj->_row.set(col, ctx.unbox(value)); + } + } + else { + obj->_row.set_null(col); + } + }); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, + ColKey key, __unsafe_unretained NSDate *const date) { + setValueOrNull(obj, key, date); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSData *const value) { + setValueOrNull(obj, key, value); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSString *const value) { + setValueOrNull(obj, key, value); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained RLMObjectBase *const val) { + if (!val) { + obj->_row.set(key, realm::null()); + return; + } + + if (!val->_row) { + RLMAccessorContext{obj, key}.createObject(val, {.create = true}, false, {}); + } + + // make sure it is the correct type + auto table = val->_row.get_table(); + if (table != obj->_row.get_table()->get_link_target(key)) { + @throw RLMException(@"Can't set object of type '%@' to property of type '%@'", + val->_objectSchema.className, + obj->_info->propertyForTableColumn(key).objectClassName); + } + if (!table->is_embedded()) { + obj->_row.set(key, val->_row.get_key()); + } + else if (obj->_row.get_linked_object(key).get_key() != val->_row.get_key()) { + @throw RLMException(@"Can't set link to existing managed embedded object"); + } +} + +id RLMCollectionClassForProperty(RLMProperty *prop, bool isManaged) { + Class cls = nil; + if (prop.array) { + cls = isManaged ? [RLMManagedArray class] : [RLMArray class]; + } else if (prop.set) { + cls = isManaged ? [RLMManagedSet class] : [RLMSet class]; + } else if (prop.dictionary) { + cls = isManaged ? [RLMManagedDictionary class] : [RLMDictionary class]; + } else { + @throw RLMException(@"Invalid collection '%@' for class '%@'.", + prop.name, prop.objectClassName); + } + return cls; +} + +// collection getter/setter +id getCollection(__unsafe_unretained RLMObjectBase *const obj, NSUInteger propIndex) { + RLMVerifyAttached(obj); + auto prop = obj->_info->rlmObjectSchema.properties[propIndex]; + Class cls = RLMCollectionClassForProperty(prop, true); + return [[cls alloc] initWithParent:obj property:prop]; +} + +template +void assignValue(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained RLMProperty *const prop, + ColKey key, + __unsafe_unretained id const value) { + auto info = obj->_info; + Collection collection(obj->_realm->_realm, obj->_row, key); + if (collection.get_type() == realm::PropertyType::Object) { + info = &obj->_info->linkTargetType(prop.index); + } + RLMAccessorContext ctx(*info); + RLMTranslateError([&] { + collection.assign(ctx, value, realm::CreatePolicy::ForceCreate); + }); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained id const value) { + auto prop = obj->_info->propertyForTableColumn(key); + RLMValidateValueForProperty(value, obj->_info->rlmObjectSchema, prop, true); + + if (prop.array) { + assignValue(obj, prop, key, value); + } + else if (prop.set) { + assignValue(obj, prop, key, value); + } + else if (prop.dictionary) { + assignValue(obj, prop, key, value); + } +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSNumber *const intObject) { + setValueOrNull(obj, key, intObject); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSNumber *const floatObject) { + setValueOrNull(obj, key, floatObject); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSNumber *const doubleObject) { + setValueOrNull(obj, key, doubleObject); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSNumber *const boolObject) { + setValueOrNull(obj, key, boolObject); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained RLMDecimal128 *const value) { + setValueOrNull(obj, key, value); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained RLMObjectId *const value) { + setValueOrNull(obj, key, value); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSUUID *const value) { + setValueOrNull(obj, key, value); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained id const value) { + setValueOrNull(obj, key, value); +} + +RLMLinkingObjects *getLinkingObjects(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained RLMProperty *const property) { + RLMVerifyAttached(obj); + auto& objectInfo = obj->_realm->_info[property.objectClassName]; + auto& linkOrigin = obj->_info->objectSchema->computed_properties[property.index].link_origin_property_name; + auto linkingProperty = objectInfo.objectSchema->property_for_name(linkOrigin); + auto backlinkView = obj->_row.get_backlink_view(objectInfo.table(), linkingProperty->column_key); + realm::Results results(obj->_realm->_realm, std::move(backlinkView)); + return [RLMLinkingObjects resultsWithObjectInfo:objectInfo results:std::move(results)]; +} + +// any getter/setter +template +id makeGetter(NSUInteger index) { + return ^(__unsafe_unretained RLMObjectBase *const obj) { + return static_cast(get(obj, index)); + }; +} + +template +id makeBoxedGetter(NSUInteger index) { + return ^(__unsafe_unretained RLMObjectBase *const obj) { + return getBoxed(obj, index); + }; +} +template +id makeOptionalGetter(NSUInteger index) { + return ^(__unsafe_unretained RLMObjectBase *const obj) { + return getBoxed>(obj, index); + }; +} +template +id makeNumberGetter(NSUInteger index, bool boxed, bool optional) { + if (optional) { + return makeOptionalGetter(index); + } + if (boxed) { + return makeBoxedGetter(index); + } + return makeGetter(index); +} +template +id makeWrapperGetter(NSUInteger index, bool optional) { + if (optional) { + return makeOptionalGetter(index); + } + return makeBoxedGetter(index); +} + +// dynamic getter with column closure +id managedGetter(RLMProperty *prop, const char *type) { + NSUInteger index = prop.index; + if (prop.collection && prop.type != RLMPropertyTypeLinkingObjects) { + return ^id(__unsafe_unretained RLMObjectBase *const obj) { + return getCollection(obj, index); + }; + } + + bool boxed = *type == '@'; + switch (prop.type) { + case RLMPropertyTypeInt: + if (prop.optional || boxed) { + return makeNumberGetter(index, boxed, prop.optional); + } + switch (*type) { + case 'c': return makeGetter(index); + case 's': return makeGetter(index); + case 'i': return makeGetter(index); + case 'l': return makeGetter(index); + case 'q': return makeGetter(index); + default: + @throw RLMException(@"Unexpected property type for Objective-C type code"); + } + case RLMPropertyTypeFloat: + return makeNumberGetter(index, boxed, prop.optional); + case RLMPropertyTypeDouble: + return makeNumberGetter(index, boxed, prop.optional); + case RLMPropertyTypeBool: + return makeNumberGetter(index, boxed, prop.optional); + case RLMPropertyTypeString: + return makeBoxedGetter(index); + case RLMPropertyTypeDate: + return makeBoxedGetter(index); + case RLMPropertyTypeData: + return makeBoxedGetter(index); + case RLMPropertyTypeObject: + return makeBoxedGetter(index); + case RLMPropertyTypeDecimal128: + return makeBoxedGetter(index); + case RLMPropertyTypeObjectId: + return makeWrapperGetter(index, prop.optional); + case RLMPropertyTypeAny: + // Mixed is represented as optional in Core, + // but not in Cocoa. We use `makeBoxedGetter` over + // `makeWrapperGetter` becuase Mixed can box a `null` representation. + return makeBoxedGetter(index); + case RLMPropertyTypeLinkingObjects: + return ^(__unsafe_unretained RLMObjectBase *const obj) { + return getLinkingObjects(obj, prop); + }; + case RLMPropertyTypeUUID: + return makeWrapperGetter(index, prop.optional); + } +} + +static realm::ColKey willChange(RLMObservationTracker& tracker, + __unsafe_unretained RLMObjectBase *const obj, NSUInteger index) { + auto& prop = getProperty(obj, index); + if (prop.is_primary) { + @throw RLMException(@"Primary key can't be changed after an object is inserted."); + } + tracker.willChange(RLMGetObservationInfo(obj->_observationInfo, obj->_row.get_key(), *obj->_info), + obj->_objectSchema.properties[index].name); + return prop.column_key; +} + +template +void kvoSetValue(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index, ArgType value) { + RLMVerifyInWriteTransaction(obj); + RLMObservationTracker tracker(obj->_realm); + auto key = willChange(tracker, obj, index); + if constexpr (std::is_same_v) { + tracker.trackDeletions(); + } + setValue(obj, key, static_cast(value)); +} + +template +id makeSetter(__unsafe_unretained RLMProperty *const prop) { + if (prop.isPrimary) { + return ^(__unused RLMObjectBase *obj, __unused ArgType val) { + @throw RLMException(@"Primary key can't be changed after an object is inserted."); + }; + } + + NSUInteger index = prop.index; + return ^(__unsafe_unretained RLMObjectBase *const obj, ArgType val) { + kvoSetValue(obj, index, val); + }; +} + +// dynamic setter with column closure +id managedSetter(RLMProperty *prop, const char *type) { + if (prop.collection && prop.type != RLMPropertyTypeLinkingObjects) { + return makeSetter>(prop); + } + + bool boxed = prop.optional || *type == '@'; + switch (prop.type) { + case RLMPropertyTypeInt: + if (boxed) { + return makeSetter *>(prop); + } + switch (*type) { + case 'c': return makeSetter(prop); + case 's': return makeSetter(prop); + case 'i': return makeSetter(prop); + case 'l': return makeSetter(prop); + case 'q': return makeSetter(prop); + default: + @throw RLMException(@"Unexpected property type for Objective-C type code"); + } + case RLMPropertyTypeFloat: + return boxed ? makeSetter *>(prop) : makeSetter(prop); + case RLMPropertyTypeDouble: + return boxed ? makeSetter *>(prop) : makeSetter(prop); + case RLMPropertyTypeBool: + return boxed ? makeSetter *>(prop) : makeSetter(prop); + case RLMPropertyTypeString: return makeSetter(prop); + case RLMPropertyTypeDate: return makeSetter(prop); + case RLMPropertyTypeData: return makeSetter(prop); + case RLMPropertyTypeAny: return makeSetter>(prop); + case RLMPropertyTypeLinkingObjects: return nil; + case RLMPropertyTypeObject: return makeSetter(prop); + case RLMPropertyTypeObjectId: return makeSetter(prop); + case RLMPropertyTypeDecimal128: return makeSetter(prop); + case RLMPropertyTypeUUID: return makeSetter(prop); + } +} + +// call getter for superclass for property at key +id superGet(RLMObjectBase *obj, NSString *propName) { + typedef id (*getter_type)(RLMObjectBase *, SEL); + RLMProperty *prop = obj->_objectSchema[propName]; + Class superClass = class_getSuperclass(obj.class); + getter_type superGetter = (getter_type)[superClass instanceMethodForSelector:prop.getterSel]; + return superGetter(obj, prop.getterSel); +} + +// call setter for superclass for property at key +void superSet(RLMObjectBase *obj, NSString *propName, id val) { + typedef void (*setter_type)(RLMObjectBase *, SEL, id collection); + RLMProperty *prop = obj->_objectSchema[propName]; + Class superClass = class_getSuperclass(obj.class); + setter_type superSetter = (setter_type)[superClass instanceMethodForSelector:prop.setterSel]; + superSetter(obj, prop.setterSel, val); +} + +// getter/setter for unmanaged object +id unmanagedGetter(RLMProperty *prop, const char *) { + // only override getters for RLMCollection and linking objects properties + if (prop.type == RLMPropertyTypeLinkingObjects) { + return ^(RLMObjectBase *) { return [RLMResults emptyDetachedResults]; }; + } + if (prop.collection) { + NSString *propName = prop.name; + Class cls = RLMCollectionClassForProperty(prop, false); + if (prop.type == RLMPropertyTypeObject) { + NSString *objectClassName = prop.objectClassName; + RLMPropertyType keyType = prop.dictionaryKeyType; + return ^(RLMObjectBase *obj) { + id val = superGet(obj, propName); + if (!val) { + val = [[cls alloc] initWithObjectClassName:objectClassName keyType:keyType]; + superSet(obj, propName, val); + } + return val; + }; + } + auto type = prop.type; + auto optional = prop.optional; + auto dictionaryKeyType = prop.dictionaryKeyType; + return ^(RLMObjectBase *obj) { + id val = superGet(obj, propName); + if (!val) { + val = [[cls alloc] initWithObjectType:type optional:optional keyType:dictionaryKeyType]; + superSet(obj, propName, val); + } + return val; + }; + } + return nil; +} + +id unmanagedSetter(RLMProperty *prop, const char *) { + // Only RLMCollection types need special handling for the unmanaged setter + if (!prop.collection) { + return nil; + } + + NSString *propName = prop.name; + return ^(RLMObjectBase *obj, id values) { + auto prop = obj->_objectSchema[propName]; + RLMValidateValueForProperty(values, obj->_objectSchema, prop, true); + + Class cls = RLMCollectionClassForProperty(prop, false); + id collection; + // make copy when setting (as is the case for all other variants) + if (prop.type == RLMPropertyTypeObject) { + collection = [[cls alloc] initWithObjectClassName:prop.objectClassName keyType:prop.dictionaryKeyType]; + } + else { + collection = [[cls alloc] initWithObjectType:prop.type optional:prop.optional keyType:prop.dictionaryKeyType]; + } + + if (prop.dictionary) + [collection addEntriesFromDictionary:(id)values]; + else + [collection addObjects:values]; + superSet(obj, propName, collection); + }; +} + +void addMethod(Class cls, __unsafe_unretained RLMProperty *const prop, + id (*getter)(RLMProperty *, const char *), + id (*setter)(RLMProperty *, const char *)) { + SEL sel = prop.getterSel; + if (!sel) { + return; + } + auto getterMethod = class_getInstanceMethod(cls, sel); + if (!getterMethod) { + return; + } + + const char *getterType = method_getTypeEncoding(getterMethod); + if (id block = getter(prop, getterType)) { + class_addMethod(cls, sel, imp_implementationWithBlock(block), getterType); + } + + if (!(sel = prop.setterSel)) { + return; + } + auto setterMethod = class_getInstanceMethod(cls, sel); + if (!setterMethod) { + return; + } + if (id block = setter(prop, getterType)) { // note: deliberately getterType as it's easier to grab the relevant type from + class_addMethod(cls, sel, imp_implementationWithBlock(block), method_getTypeEncoding(setterMethod)); + } +} + +Class createAccessorClass(Class objectClass, + RLMObjectSchema *schema, + const char *accessorClassName, + id (*getterGetter)(RLMProperty *, const char *), + id (*setterGetter)(RLMProperty *, const char *)) { + REALM_ASSERT_DEBUG(RLMIsObjectOrSubclass(objectClass)); + + // create and register proxy class which derives from object class + Class accClass = objc_allocateClassPair(objectClass, accessorClassName, 0); + if (!accClass) { + // Class with that name already exists, so just return the pre-existing one + // This should only happen for our standalone "accessors" + return objc_lookUpClass(accessorClassName); + } + + // override getters/setters for each propery + for (RLMProperty *prop in schema.properties) { + addMethod(accClass, prop, getterGetter, setterGetter); + } + for (RLMProperty *prop in schema.computedProperties) { + addMethod(accClass, prop, getterGetter, setterGetter); + } + + objc_registerClassPair(accClass); + + return accClass; +} + +bool requiresUnmanagedAccessor(RLMObjectSchema *schema) { + for (RLMProperty *prop in schema.properties) { + if (prop.collection && !prop.swiftIvar) { + return true; + } + } + for (RLMProperty *prop in schema.computedProperties) { + if (prop.collection && !prop.swiftIvar) { + return true; + } + } + return false; +} +} // anonymous namespace + +#pragma mark - Public Interface + +Class RLMManagedAccessorClassForObjectClass(Class objectClass, RLMObjectSchema *schema, const char *name) { + return createAccessorClass(objectClass, schema, name, managedGetter, managedSetter); +} + +Class RLMUnmanagedAccessorClassForObjectClass(Class objectClass, RLMObjectSchema *schema) { + if (!requiresUnmanagedAccessor(schema)) { + return objectClass; + } + return createAccessorClass(objectClass, schema, + [@"RLM:Unmanaged " stringByAppendingString:schema.className].UTF8String, + unmanagedGetter, unmanagedSetter); +} + +// implement the class method className on accessors to return the className of the +// base object +void RLMReplaceClassNameMethod(Class accessorClass, NSString *className) { + Class metaClass = object_getClass(accessorClass); + IMP imp = imp_implementationWithBlock(^(Class) { return className; }); + class_addMethod(metaClass, @selector(className), imp, "@@:"); +} + +// implement the shared schema method +void RLMReplaceSharedSchemaMethod(Class accessorClass, RLMObjectSchema *schema) { + REALM_ASSERT(accessorClass != [RealmSwiftObject class]); + Class metaClass = object_getClass(accessorClass); + IMP imp = imp_implementationWithBlock(^(Class cls) { + if (cls == accessorClass) { + return schema; + } + + // If we aren't being called directly on the class this was overridden + // for, the class is either a subclass which we haven't initialized yet, + // or it's a runtime-generated class which should use the parent's + // schema. We check for the latter by checking if the immediate + // descendent of the desired class is a class generated by us (there + // may be further subclasses not generated by us for things like KVO). + Class parent = class_getSuperclass(cls); + while (parent != accessorClass) { + cls = parent; + parent = class_getSuperclass(cls); + } + + static const char accessorClassPrefix[] = "RLM:"; + if (!strncmp(class_getName(cls), accessorClassPrefix, sizeof(accessorClassPrefix) - 1)) { + return schema; + } + + return [RLMSchema sharedSchemaForClass:cls]; + }); + class_addMethod(metaClass, @selector(sharedSchema), imp, "@@:"); +} + +void RLMDynamicValidatedSet(RLMObjectBase *obj, NSString *propName, id val) { + RLMVerifyAttached(obj); + RLMObjectSchema *schema = obj->_objectSchema; + RLMProperty *prop = schema[propName]; + if (!prop) { + @throw RLMException(@"Invalid property name '%@' for class '%@'.", + propName, obj->_objectSchema.className); + } + if (prop.isPrimary) { + @throw RLMException(@"Primary key can't be changed to '%@' after an object is inserted.", val); + } + + // Because embedded objects cannot be created directly, we accept anything + // that can be converted to an embedded object for dynamic link set operations. + bool is_embedded = prop.type == RLMPropertyTypeObject && obj->_info->linkTargetType(prop.index).rlmObjectSchema.isEmbedded; + RLMValidateValueForProperty(val, schema, prop, !is_embedded); + RLMDynamicSet(obj, prop, RLMCoerceToNil(val)); +} + +// Precondition: the property is not a primary key +void RLMDynamicSet(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained RLMProperty *const prop, + __unsafe_unretained id const val) { + REALM_ASSERT_DEBUG(!prop.isPrimary); + realm::Object o(obj->_info->realm->_realm, *obj->_info->objectSchema, obj->_row); + RLMAccessorContext c(obj); + RLMTranslateError([&] { + o.set_property_value(c, getProperty(obj, prop).name, val ?: NSNull.null); + }); +} + +id RLMDynamicGet(__unsafe_unretained RLMObjectBase *const obj, __unsafe_unretained RLMProperty *const prop) { + if (auto accessor = prop.swiftAccessor; accessor && [obj isKindOfClass:obj->_objectSchema.objectClass]) { + return RLMCoerceToNil([accessor get:prop on:obj]); + } + if (!obj->_realm) { + return [obj valueForKey:prop.name]; + } + + realm::Object o(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row); + RLMAccessorContext c(obj); + c.currentProperty = prop; + return RLMTranslateError([&] { + return RLMCoerceToNil(o.get_property_value(c, getProperty(obj, prop))); + }); +} + +id RLMDynamicGetByName(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained NSString *const propName) { + RLMProperty *prop = obj->_objectSchema[propName]; + if (!prop) { + @throw RLMException(@"Invalid property name '%@' for class '%@'.", + propName, obj->_objectSchema.className); + } + return RLMDynamicGet(obj, prop); +} + +#pragma mark - Swift property getters and setter + +#define REALM_SWIFT_PROPERTY_ACCESSOR(objc, swift, rlmtype) \ + objc RLMGetSwiftProperty##swift(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { \ + return get(obj, key); \ + } \ + objc RLMGetSwiftProperty##swift##Optional(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, bool *gotValue) { \ + return getOptional(obj, key, gotValue); \ + } \ + void RLMSetSwiftProperty##swift(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, objc value) { \ + RLMVerifyAttached(obj); \ + kvoSetValue(obj, key, value); \ + } +REALM_FOR_EACH_SWIFT_PRIMITIVE_TYPE(REALM_SWIFT_PROPERTY_ACCESSOR) +#undef REALM_SWIFT_PROPERTY_ACCESSOR + +#define REALM_SWIFT_PROPERTY_ACCESSOR(objc, swift, rlmtype) \ + void RLMSetSwiftProperty##swift(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, objc *value) { \ + RLMVerifyAttached(obj); \ + kvoSetValue(obj, key, value); \ + } +REALM_FOR_EACH_SWIFT_OBJECT_TYPE(REALM_SWIFT_PROPERTY_ACCESSOR) +#undef REALM_SWIFT_PROPERTY_ACCESSOR + +NSString *RLMGetSwiftPropertyString(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed(obj, key); +} + +NSData *RLMGetSwiftPropertyData(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed(obj, key); +} + +NSDate *RLMGetSwiftPropertyDate(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed(obj, key); +} + +NSUUID *RLMGetSwiftPropertyUUID(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed>(obj, key); +} + +RLMObjectId *RLMGetSwiftPropertyObjectId(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed>(obj, key); +} + +RLMDecimal128 *RLMGetSwiftPropertyDecimal128(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed(obj, key); +} + +RLMArray *RLMGetSwiftPropertyArray(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getCollection(obj, key); +} +RLMSet *RLMGetSwiftPropertySet(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getCollection(obj, key); +} +RLMDictionary *RLMGetSwiftPropertyMap(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getCollection(obj, key); +} + +void RLMSetSwiftPropertyNil(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + RLMVerifyInWriteTransaction(obj); + if (getProperty(obj, key).type == realm::PropertyType::Object) { + kvoSetValue(obj, key, (RLMObjectBase *)nil); + } + else { + // The type used here is arbitrary; it simply needs to be any non-object type + kvoSetValue(obj, key, (NSNumber *)nil); + } +} + +void RLMSetSwiftPropertyObject(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, + __unsafe_unretained RLMObjectBase *const target) { + kvoSetValue(obj, key, target); +} + +RLMObjectBase *RLMGetSwiftPropertyObject(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed(obj, key); +} + +void RLMSetSwiftPropertyAny(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, + __unsafe_unretained id const value) { + kvoSetValue(obj, key, value); +} + +id RLMGetSwiftPropertyAny(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed(obj, key); +} + +#pragma mark - RLMAccessorContext + +RLMAccessorContext::~RLMAccessorContext() = default; + +RLMAccessorContext::RLMAccessorContext(RLMAccessorContext& parent, realm::Obj const& obj, + realm::Property const& property) +: _realm(parent._realm) +, _info(property.type == realm::PropertyType::Object ? parent._info.linkTargetType(property) : parent._info) +, _parentObject(obj) +, _parentObjectInfo(&parent._info) +, _colKey(property.column_key) +{ +} + +RLMAccessorContext::RLMAccessorContext(RLMClassInfo& info) +: _realm(info.realm), _info(info) +{ +} + +RLMAccessorContext::RLMAccessorContext(__unsafe_unretained RLMObjectBase *const parent, + const realm::Property *prop) +: _realm(parent->_realm) +, _info(prop && prop->type == realm::PropertyType::Object ? parent->_info->linkTargetType(*prop) + : *parent->_info) +, _parentObject(parent->_row) +, _parentObjectInfo(parent->_info) +, _colKey(prop ? prop->column_key : ColKey{}) +{ +} + +RLMAccessorContext::RLMAccessorContext(__unsafe_unretained RLMObjectBase *const parent, + realm::ColKey col) +: _realm(parent->_realm) +, _info(_realm->_info[parent->_info->propertyForTableColumn(col).objectClassName]) +, _parentObject(parent->_row) +, _parentObjectInfo(parent->_info) +, _colKey(col) +{ +} + +id RLMAccessorContext::defaultValue(__unsafe_unretained NSString *const key) { + if (!_defaultValues) { + _defaultValues = RLMDefaultValuesForObjectSchema(_info.rlmObjectSchema); + } + return _defaultValues[key]; +} + +id RLMAccessorContext::propertyValue(id obj, size_t propIndex, + __unsafe_unretained RLMProperty *const prop) { + obj = RLMBridgeSwiftValue(obj) ?: obj; + + // Property value from an NSArray + if ([obj respondsToSelector:@selector(objectAtIndex:)]) { + return propIndex < [obj count] ? [obj objectAtIndex:propIndex] : nil; + } + + // Property value from an NSDictionary + if ([obj respondsToSelector:@selector(objectForKey:)]) { + return [obj objectForKey:prop.name]; + } + + // Property value from an instance of this object type + if ([obj isKindOfClass:_info.rlmObjectSchema.objectClass] && prop.swiftAccessor) { + return [prop.swiftAccessor get:prop on:obj]; + } + + // Property value from some object that's KVC-compatible + id value = RLMValidatedValueForProperty(obj, [obj respondsToSelector:prop.getterSel] ? prop.getterName : prop.name, + _info.rlmObjectSchema.className); + return value ?: NSNull.null; +} + +realm::Obj RLMAccessorContext::create_embedded_object() { + if (!_parentObject) { + @throw RLMException(@"Embedded objects cannot be created directly"); + } + return _parentObject.create_and_set_linked_object(_colKey); +} + +id RLMAccessorContext::box(realm::Mixed v) { + return RLMMixedToObjc(v, _realm, &_info); +} + +id RLMAccessorContext::box(realm::List&& l) { + REALM_ASSERT(_parentObjectInfo); + REALM_ASSERT(currentProperty); + return [[RLMManagedArray alloc] initWithBackingCollection:std::move(l) + parentInfo:_parentObjectInfo + property:currentProperty]; +} + +id RLMAccessorContext::box(realm::object_store::Set&& s) { + REALM_ASSERT(_parentObjectInfo); + REALM_ASSERT(currentProperty); + return [[RLMManagedSet alloc] initWithBackingCollection:std::move(s) + parentInfo:_parentObjectInfo + property:currentProperty]; +} + +id RLMAccessorContext::box(realm::object_store::Dictionary&& d) { + REALM_ASSERT(_parentObjectInfo); + REALM_ASSERT(currentProperty); + return [[RLMManagedDictionary alloc] initWithBackingCollection:std::move(d) + parentInfo:_parentObjectInfo + property:currentProperty]; +} + +id RLMAccessorContext::box(realm::Object&& o) { + REALM_ASSERT(currentProperty); + return RLMCreateObjectAccessor(_info.linkTargetType(currentProperty.index), o.get_obj()); +} + +id RLMAccessorContext::box(realm::Obj&& r) { + if (!currentProperty) { + // If currentProperty is set, then we're reading from a Collection and + // that reported an audit read for us. If not, we need to report the + // audit read. This happens automatically when creating a + // `realm::Object`, but our object accessors don't wrap that type. + realm::Object(_realm->_realm, *_info.objectSchema, r, _parentObject, _colKey); + } + return RLMCreateObjectAccessor(_info, std::move(r)); +} + +id RLMAccessorContext::box(realm::Results&& r) { + REALM_ASSERT(currentProperty); + return [RLMResults resultsWithObjectInfo:_realm->_info[currentProperty.objectClassName] + results:std::move(r)]; +} + +using realm::ObjKey; +using realm::CreatePolicy; + +template +static T *bridged(__unsafe_unretained id const value) { + return [value isKindOfClass:[T class]] ? value : RLMBridgeSwiftValue(value); +} + +template<> +realm::Timestamp RLMStatelessAccessorContext::unbox(__unsafe_unretained id const value) { + id v = RLMCoerceToNil(value); + return RLMTimestampForNSDate(bridged(v)); +} + +template<> +bool RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return [bridged(v) boolValue]; +} +template<> +double RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return [bridged(v) doubleValue]; +} +template<> +float RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return [bridged(v) floatValue]; +} +template<> +long long RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return [bridged(v) longLongValue]; +} +template<> +realm::BinaryData RLMStatelessAccessorContext::unbox(id v) { + v = RLMCoerceToNil(v); + return RLMBinaryDataForNSData(bridged(v)); +} +template<> +realm::StringData RLMStatelessAccessorContext::unbox(id v) { + v = RLMCoerceToNil(v); + return RLMStringDataWithNSString(bridged(v)); +} +template<> +realm::Decimal128 RLMStatelessAccessorContext::unbox(id v) { + return RLMObjcToDecimal128(v); +} +template<> +realm::ObjectId RLMStatelessAccessorContext::unbox(id v) { + return bridged(v).value; +} +template<> +realm::UUID RLMStatelessAccessorContext::unbox(id v) { + return RLMObjcToUUID(bridged(v)); +} +template<> +realm::Mixed RLMAccessorContext::unbox(__unsafe_unretained id v, CreatePolicy p, ObjKey) { + return RLMObjcToMixed(v, _realm, p); +} + +template +static auto toOptional(__unsafe_unretained id const value) { + id v = RLMCoerceToNil(value); + return v ? realm::util::make_optional(RLMStatelessAccessorContext::unbox(v)) + : realm::util::none; +} + +template<> +std::optional RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return toOptional(v); +} +template<> +std::optional RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return toOptional(v); +} +template<> +std::optional RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return toOptional(v); +} +template<> +std::optional RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return toOptional(v); +} +template<> +std::optional RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return toOptional(v); +} +template<> +std::optional RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return toOptional(v); +} + +std::pair +RLMAccessorContext::createObject(id value, realm::CreatePolicy policy, + bool forceCreate, ObjKey existingKey) { + if (!value || value == NSNull.null) { + @throw RLMException(@"Must provide a non-nil value."); + } + + if ([value isKindOfClass:[NSArray class]] && [value count] > _info.objectSchema->persisted_properties.size()) { + @throw RLMException(@"Invalid array input: more values (%llu) than properties (%llu).", + (unsigned long long)[value count], + (unsigned long long)_info.objectSchema->persisted_properties.size()); + } + + RLMObjectBase *objBase = RLMDynamicCast(value); + realm::Obj obj, *outObj = nullptr; + bool requiresSwiftUIObservers = false; + if (objBase) { + if (objBase.isInvalidated) { + if (policy.create && !policy.copy) { + @throw RLMException(@"Adding a deleted or invalidated object to a Realm is not permitted"); + } + else { + @throw RLMException(@"Object has been deleted or invalidated."); + } + } + if (policy.copy) { + if (policy.update || !forceCreate) { + // create(update: true) is a no-op when given an object already in + // the Realm which is of the correct type + if (objBase->_realm == _realm && objBase->_row.get_table() == _info.table() && !_info.table()->is_embedded()) { + return {objBase->_row, true}; + } + } + // Otherwise we copy the object + objBase = nil; + } + else { + outObj = &objBase->_row; + // add() on an object already managed by this Realm is a no-op + if (objBase->_realm == _realm) { + return {objBase->_row, true}; + } + if (!policy.create) { + return {realm::Obj(), false}; + } + if (objBase->_realm) { + @throw RLMException(@"Object is already managed by another Realm. Use create instead to copy it into this Realm."); + } + if (objBase->_observationInfo && objBase->_observationInfo->hasObservers()) { + requiresSwiftUIObservers = [RLMSwiftUIKVO removeObserversFromObject:objBase]; + if (!requiresSwiftUIObservers) { + @throw RLMException(@"Cannot add an object with observers to a Realm"); + } + } + + REALM_ASSERT([objBase->_objectSchema.className isEqualToString:_info.rlmObjectSchema.className]); + REALM_ASSERT([objBase isKindOfClass:_info.rlmObjectSchema.unmanagedClass]); + + objBase->_info = &_info; + objBase->_realm = _realm; + objBase->_objectSchema = _info.rlmObjectSchema; + } + } + if (!policy.create) { + return {realm::Obj(), false}; + } + if (!outObj) { + outObj = &obj; + } + + try { + realm::Object::create(*this, _realm->_realm, *_info.objectSchema, + (id)value, policy, existingKey, outObj); + } + catch (std::exception const& e) { + @throw RLMException(e); + } + + if (objBase) { + for (RLMProperty *prop in _info.rlmObjectSchema.properties) { + // set the ivars for object and array properties to nil as otherwise the + // accessors retain objects that are no longer accessible via the properties + // this is mainly an issue when the object graph being added has cycles, + // as it's not obvious that the user has to set the *ivars* to nil to + // avoid leaking memory + if (prop.type == RLMPropertyTypeObject && !prop.swiftIvar) { + ((void(*)(id, SEL, id))objc_msgSend)(objBase, prop.setterSel, nil); + } + } + + object_setClass(objBase, _info.rlmObjectSchema.accessorClass); + RLMInitializeSwiftAccessor(objBase, true); + } + + if (requiresSwiftUIObservers) { + [RLMSwiftUIKVO addObserversToObject:objBase]; + } + + return {*outObj, false}; +} + +template<> +realm::Obj RLMAccessorContext::unbox(__unsafe_unretained id const v, CreatePolicy policy, ObjKey key) { + return createObject(v, policy, false, key).first; +} + +void RLMAccessorContext::will_change(realm::Obj const& row, realm::Property const& prop) { + auto obsInfo = RLMGetObservationInfo(nullptr, row.get_key(), _info); + if (!_observationHelper) { + if (obsInfo || prop.type == realm::PropertyType::Object) { + _observationHelper = std::make_unique(_info.realm); + } + } + if (_observationHelper) { + _observationHelper->willChange(obsInfo, _info.propertyForTableColumn(prop.column_key).name); + if (prop.type == realm::PropertyType::Object) { + _observationHelper->trackDeletions(); + } + } +} + +void RLMAccessorContext::did_change() { + if (_observationHelper) { + _observationHelper->didChange(); + } +} + +RLMOptionalId RLMAccessorContext::value_for_property(__unsafe_unretained id const obj, + realm::Property const&, size_t propIndex) { + auto prop = _info.rlmObjectSchema.properties[propIndex]; + id value = propertyValue(obj, propIndex, prop); + if (value) { + RLMValidateValueForProperty(value, _info.rlmObjectSchema, prop); + } + return RLMOptionalId{value}; +} + +RLMOptionalId RLMAccessorContext::default_value_for_property(realm::ObjectSchema const&, + realm::Property const& prop) +{ + return RLMOptionalId{defaultValue(@(prop.name.c_str()))}; +} + +bool RLMStatelessAccessorContext::is_same_list(realm::List const& list, + __unsafe_unretained id const v) noexcept { + return [v respondsToSelector:@selector(isBackedByList:)] && [v isBackedByList:list]; +} + +bool RLMStatelessAccessorContext::is_same_set(realm::object_store::Set const& set, + __unsafe_unretained id const v) noexcept { + return [v respondsToSelector:@selector(isBackedBySet:)] && [v isBackedBySet:set]; +} + +bool RLMStatelessAccessorContext::is_same_dictionary(realm::object_store::Dictionary const& dict, + __unsafe_unretained id const v) noexcept { + return [v respondsToSelector:@selector(isBackedByDictionary:)] && [v isBackedByDictionary:dict]; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincomplete-implementation" +@implementation RLMManagedPropertyAccessor +// Most types don't need to distinguish between promote and init so provide a default ++ (void)promote:(RLMProperty *)property on:(RLMObjectBase *)parent { + [self initialize:property on:parent]; +} +@end +#pragma clang diagnostic pop diff --git a/Pods/Realm/Realm/RLMAnalytics.mm b/Pods/Realm/Realm/RLMAnalytics.mm new file mode 100644 index 0000000..0806e77 --- /dev/null +++ b/Pods/Realm/Realm/RLMAnalytics.mm @@ -0,0 +1,425 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +// Asynchronously submits build information to Realm if running in an iOS +// simulator or on OS X if a debugger is attached. Does nothing if running on an +// iOS / watchOS device or if a debugger is *not* attached. +// +// To be clear: this does *not* run when your app is in production or on +// your end-user’s devices; it will only run in the simulator or when a debugger +// is attached. +// +// Why are we doing this? In short, because it helps us build a better product +// for you. None of the data personally identifies you, your employer or your +// app, but it *will* help us understand what language you use, what iOS +// versions you target, etc. Having this info will help prioritizing our time, +// adding new features and deprecating old features. Collecting an anonymized +// bundle & anonymized MAC is the only way for us to count actual usage of the +// other metrics accurately. If we don’t have a way to deduplicate the info +// reported, it will be useless, as a single developer building their Swift app +// 10 times would report 10 times more than a single Objective-C developer that +// only builds once, making the data all but useless. +// No one likes sharing data unless it’s necessary, we get it, and we’ve +// debated adding this for a long long time. Since Realm is a free product +// without an email signup, we feel this is a necessary step so we can collect +// relevant data to build a better product for you. If you truly, absolutely +// feel compelled to not send this data back to Realm, then you can set an env +// variable named REALM_DISABLE_ANALYTICS. Since Realm is free we believe +// letting these analytics run is a small price to pay for the product & support +// we give you. +// +// Currently the following information is reported: +// - What version of Realm and core is being used, and from which language (obj-c or Swift). +// - Which platform and version of OS X it's running on (in case Xcode aggressively drops +// support for older versions again, we need to know what we need to support). +// - The minimum iOS/OS X version that the application is targeting (again, to +// help us decide what versions we need to support). +// - An anonymous MAC address and bundle ID to aggregate the other information on. +// - The host platform OSX and version. +// - The XCode version. +// - Some info about the features been used when opening the realm for the first time. + +#import "RLMAnalytics.hpp" + +#import + +#if TARGET_IPHONE_SIMULATOR || TARGET_OS_MAC || (TARGET_OS_WATCH && TARGET_OS_SIMULATOR) || (TARGET_OS_TV && TARGET_OS_SIMULATOR) +#import "RLMObjectSchema_Private.h" +#import "RLMRealmConfiguration_Private.h" +#import "RLMSchema_Private.h" +#import "RLMSyncConfiguration.h" +#import "RLMUtil.hpp" + +#import +#import +#import +#import +#import + +#import + +#ifndef REALM_COCOA_VERSION +#import "RLMVersion.h" +#endif + +// Wrapper for sysctl() that handles the memory management stuff +static auto RLMSysCtl(int *mib, u_int mibSize, size_t *bufferSize) { + std::unique_ptr buffer(nullptr, &free); + + int ret = sysctl(mib, mibSize, nullptr, bufferSize, nullptr, 0); + if (ret != 0) { + return buffer; + } + + buffer.reset(malloc(*bufferSize)); + if (!buffer) { + return buffer; + } + + ret = sysctl(mib, mibSize, buffer.get(), bufferSize, nullptr, 0); + if (ret != 0) { + buffer.reset(); + } + + return buffer; +} + +// Get the version of OS X we're running on (even in the simulator this gives +// the OS X version and not the simulated iOS version) +static NSString *RLMHostOSVersion() { + size_t size; + sysctlbyname("kern.osproductversion", NULL, &size, NULL, 0); + char *model = (char*)malloc(size); + sysctlbyname("kern.osproductversion", model, &size, NULL, 0); + NSString *deviceModel = [NSString stringWithCString:model encoding:NSUTF8StringEncoding]; + free(model); + return deviceModel; +} + +static NSString *RLMTargetArch() { + NSString *targetArchitecture; +#if TARGET_CPU_X86_64 + targetArchitecture = @"x86_64"; +#elif TARGET_CPU_ARM64 + targetArchitecture = @"arm64"; +#endif + return targetArchitecture; +} + +// Hash the data in the given buffer and convert it to a hex-format string +NSString *RLMHashBase16Data(const void *bytes, size_t length) { + unsigned char buffer[CC_SHA256_DIGEST_LENGTH]; + CC_SHA256(bytes, static_cast(length), buffer); + + char formatted[CC_SHA256_DIGEST_LENGTH * 2 + 1]; + for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; ++i) { + snprintf(formatted + i * 2, sizeof(formatted) - i * 2, "%02x", buffer[i]); + } + + return [[NSString alloc] initWithBytes:formatted + length:CC_SHA256_DIGEST_LENGTH * 2 + encoding:NSUTF8StringEncoding]; +} + +static std::optional> getMacAddress(int id) { + char buff[] = "en0"; + snprintf(buff + 2, 2, "%d", id); + int index = static_cast(if_nametoindex(buff)); + if (!index) { + return std::nullopt; + } + + std::array mib = {{CTL_NET, PF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, index}}; + size_t bufferSize; + auto buffer = RLMSysCtl(&mib[0], mib.size(), &bufferSize); + if (!buffer) { + return std::nullopt; + } + + // sockaddr_dl struct is immediately after the if_msghdr struct in the buffer + auto sockaddr = reinterpret_cast(static_cast(buffer.get()) + 1); + std::array mac; + std::memcpy(&mac[0], sockaddr->sdl_data + sockaddr->sdl_nlen, 6); + + // Touch bar internal network interface, which is identical on all touch bar macs + if (mac == std::array{0xAC, 0xDE, 0x48, 0x00, 0x11, 0x22}) { + return std::nullopt; + } + + // The mac address reported on iOS. It's unclear how we're seeing this as + // this code doesn't run on iOS, but it somehow sometimes happens. + if (mac == std::array{2, 0, 0, 0, 0, 0}) { + return std::nullopt; + } + + return mac; +} + +// Returns the hash of the MAC address of the first network adaptor since the +// vendorIdentifier isn't constant between iOS simulators. +static NSString *RLMMACAddress() { + for (int i = 0; i < 9; ++i) { + if (auto mac = getMacAddress(i)) { + return RLMHashBase16Data(&(*mac)[0], 6); + } + } + return @"unknown"; + } + +static NSString *RLMBuilderId() { +#ifdef REALM_IOPLATFORMUUID + NSString *saltedId = [@"Realm is great" stringByAppendingString:REALM_IOPLATFORMUUID]; + NSData *data = [saltedId dataUsingEncoding:NSUTF8StringEncoding]; + + unsigned char buffer[CC_SHA256_DIGEST_LENGTH]; + CC_SHA256(data.bytes, static_cast(data.length), buffer); + NSData* hashedData = [NSData dataWithBytes:buffer length:CC_SHA256_DIGEST_LENGTH]; + + // Base64 Encoding + return [hashedData base64EncodedStringWithOptions:kNilOptions]; +#else + return nil; +#endif +} + +static NSDictionary *RLMBaseMetrics() { + static NSString *kUnknownString = @"unknown"; + NSBundle *appBundle = NSBundle.mainBundle; + NSString *hashedBundleID = appBundle.bundleIdentifier; + + // Main bundle isn't always the one of interest (e.g. when running tests + // it's xctest rather than the app's bundle), so look for one with a bundle ID + if (!hashedBundleID) { + for (NSBundle *bundle in NSBundle.allBundles) { + if ((hashedBundleID = bundle.bundleIdentifier)) { + appBundle = bundle; + break; + } + } + } + + // If we found a bundle ID anywhere, hash it as it could contain sensitive + // information (e.g. the name of an unannounced product) + if (hashedBundleID) { + NSData *data = [hashedBundleID dataUsingEncoding:NSUTF8StringEncoding]; + hashedBundleID = RLMHashBase16Data(data.bytes, data.length); + } + + Class swiftDecimal128 = NSClassFromString(@"RealmSwiftDecimal128"); + BOOL isSwift = swiftDecimal128 != nil; + + NSString *hashedDistinctId = RLMMACAddress(); + // We use the IOPlatformUUID if is available (Cocoapods, SPM), + // in case we cannot obtain it (Pre-built binaries) we use the hashed mac address. + NSString *hashedBuilderId = RLMBuilderId() ?: hashedDistinctId; + + NSDictionary *info = appBundle.infoDictionary; + + return @{ + // MixPanel properties + @"token": @"ce0fac19508f6c8f20066d345d360fd0", + + // Anonymous identifiers to deduplicate events + @"distinct_id": hashedDistinctId, + @"builder_id": hashedBuilderId, + + @"Anonymized MAC Address": hashedDistinctId, + @"Anonymized Bundle ID": hashedBundleID ?: kUnknownString, + + // SDK Info + @"Binding": @"cocoa", + // Which version of Realm is being used + @"Realm Version": REALM_COCOA_VERSION, + @"Core Version": @REALM_VERSION, + + // Language Info + @"Language": isSwift ? @"swift" : @"objc", + + // Target Info + // Current OS version the app is targeting + @"Target OS Version": [[NSProcessInfo processInfo] operatingSystemVersionString], + // Minimum OS version the app is targeting + @"Target OS Minimum Version": info[@"MinimumOSVersion"] ?: info[@"LSMinimumSystemVersion"] ?: kUnknownString, +#if TARGET_OS_WATCH + @"Target OS Type": @"watchos", +#elif TARGET_OS_TV + @"Target OS Type": @"tvos", +#elif TARGET_OS_IPHONE + @"Target OS Type": @"ios", +#else + @"Target OS Type": @"macos", +#endif + @"Target CPU Arch": RLMTargetArch() ?: kUnknownString, + + // Framework +#if TARGET_OS_MACCATALYST + @"Framework": @"maccatalyst", +#endif + + // Host Info + // Host OS version being built on + @"Host OS Type": @"macos", + @"Host OS Version": RLMHostOSVersion() ?: kUnknownString, + + // Installation method +#ifdef SWIFT_PACKAGE + @"Installation Method": @"spm", +#elif defined(COCOAPODS) + @"Installation Method": @"cocoapods", +#elif defined(CARTHAGE) + @"Installation Method": @"carthage", +#elif defined(REALM_IOS_STATIC) + @"Installation Method": @"static framework", +#else + @"Installation Method": @"other", +#endif + + // Compiler Info + @"Compiler": @"clang", + @"Clang Version": @__clang_version__, + @"Clang Major Version": @__clang_major__, + }; +} + +// This will only be executed once but depending on the number of objects, could take sometime +static NSDictionary *RLMSchemaMetrics(RLMSchema *schema) { + NSMutableDictionary *featuresDictionary = [@{@"Embedded_Object": @0, + @"Asymmetric_Object": @0, + @"Object_Link": @0, + @"Mixed": @0, + @"Primitive_List": @0, + @"Primitive_Set": @0, + @"Primitive_Dictionary": @0, + @"Object_List": @0, + @"Object_Set": @0, + @"Object_Dictionary": @0, + @"Backlink": @0, + } mutableCopy]; + + for (RLMObjectSchema *objectSchema in schema.objectSchema) { + if (objectSchema.isEmbedded) { + featuresDictionary[@"Embedded_Object"] = @1; + } + if (objectSchema.isAsymmetric) { + featuresDictionary[@"Asymmetric_Object"] = @1; + } + + for (RLMProperty *property in objectSchema.properties) { + if (property.array) { + if (property.type == RLMPropertyTypeObject) { + featuresDictionary[@"Object_List"] = @1; + } else { + featuresDictionary[@"Primitive_List"] = @1; + } + continue; + } + if (property.set) { + if (property.type == RLMPropertyTypeObject) { + featuresDictionary[@"Object_Set"] = @1; + } else { + featuresDictionary[@"Primitive_Set"] = @1; + } + continue; + } + if (property.dictionary) { + if (property.type == RLMPropertyTypeObject) { + featuresDictionary[@"Object_Dictionary"] = @1; + } else { + featuresDictionary[@"Primitive_Dictionary"] = @1; + } + continue; + } + + switch (property.type) { + case RLMPropertyTypeAny: + featuresDictionary[@"Mixed"] = @1; + break; + case RLMPropertyTypeObject: + featuresDictionary[@"Object_Link"] = @1; + break; + case RLMPropertyTypeLinkingObjects: + featuresDictionary[@"Backlink"] = @1; + break; + default: + break; + } + } + } + return featuresDictionary; +} + +static NSDictionary *RLMConfigurationMetrics(RLMRealmConfiguration *configuration) { + RLMSyncConfiguration *syncConfiguration = configuration.syncConfiguration; + bool isSync = syncConfiguration != nil; + bool isPBSSync = syncConfiguration.partitionValue != nil; + bool isFlexibleSync = (isSync && !isPBSSync); + auto resetMode = syncConfiguration.clientResetMode; + + bool isCompactOnLaunch = configuration.shouldCompactOnLaunch != nil; + bool migrationBlock = configuration.migrationBlock != nil; + + return @{ + // Sync + @"Sync Enabled": isSync ? @"true" : @"false", + @"Flx_Sync": isFlexibleSync ? @1 : @0, + @"Pbs_Sync": isPBSSync ? @1 : @0, + + // Client Reset + @"CR_Recover_Discard": (isSync && resetMode == RLMClientResetModeRecoverOrDiscardUnsyncedChanges) ? @1 : @0, + @"CR_Recover": (isSync && resetMode == RLMClientResetModeRecoverUnsyncedChanges) ? @1 : @0, + @"CR_Discard": (isSync && resetMode == RLMClientResetModeDiscardUnsyncedChanges) ? @1 : @0, + @"CR_Manual": (isSync && resetMode == RLMClientResetModeManual) ? @1 : @0, + + // Configuration + @"Compact_On_Launch": isCompactOnLaunch ? @1 : @0, + @"Schema_Migration_Block": migrationBlock ? @1 : @0, + }; +} + +void RLMSendAnalytics(RLMRealmConfiguration *configuration, RLMSchema *schema) { + if (getenv("REALM_DISABLE_ANALYTICS") || !RLMIsDebuggerAttached() || RLMIsRunningInPlayground()) { + return; + } + + id config = [configuration copy]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSDictionary *baseMetrics = RLMBaseMetrics(); + NSDictionary *schemaMetrics = RLMSchemaMetrics(schema); + NSDictionary *configurationMetrics = RLMConfigurationMetrics(config); + + NSMutableDictionary *metrics = [[NSMutableDictionary alloc] init]; + [metrics addEntriesFromDictionary:baseMetrics]; + [metrics addEntriesFromDictionary:schemaMetrics]; + [metrics addEntriesFromDictionary:configurationMetrics]; + + NSDictionary *payloadN = @{@"event": @"Run", @"properties": metrics}; + NSData *payload = [NSJSONSerialization dataWithJSONObject:payloadN options:0 error:nil]; + + NSString *url = @"https://data.mongodb-api.com/app/realmsdkmetrics-zmhtm/endpoint/metric_webhook/metric?data=%@"; + NSString *formatted = [NSString stringWithFormat:url, [payload base64EncodedStringWithOptions:0]]; + // No error handling or anything because logging errors annoyed people for no + // real benefit, and it's not clear what else we could do + [[NSURLSession.sharedSession dataTaskWithURL:[NSURL URLWithString:formatted]] resume]; + }); +} + +#else + +void RLMSendAnalytics() {} + +#endif diff --git a/Pods/Realm/Realm/RLMApp.mm b/Pods/Realm/Realm/RLMApp.mm new file mode 100644 index 0000000..43323d2 --- /dev/null +++ b/Pods/Realm/Realm/RLMApp.mm @@ -0,0 +1,479 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMApp_Private.hpp" + +#import +#if __has_include() +#import +#define REALM_UIDEVICE_AVAILABLE +#endif + +#import "RLMAnalytics.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMCredentials_Private.hpp" +#import "RLMEmailPasswordAuth.h" +#import "RLMLogger.h" +#import "RLMPushClient_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import + +#if !defined(REALM_COCOA_VERSION) +#import "RLMVersion.h" +#endif + +using namespace realm; + +#pragma mark CocoaNetworkTransport +namespace { + /// Internal transport struct to bridge RLMNetworkingTransporting to the GenericNetworkTransport. + class CocoaNetworkTransport : public realm::app::GenericNetworkTransport { + public: + CocoaNetworkTransport(id transport) : m_transport(transport) {} + + void send_request_to_server(const app::Request& request, + util::UniqueFunction&& completion) override { + // Convert the app::Request to an RLMRequest + auto rlmRequest = [RLMRequest new]; + rlmRequest.url = @(request.url.data()); + rlmRequest.body = @(request.body.data()); + NSMutableDictionary *headers = [NSMutableDictionary new]; + for (auto&& header : request.headers) { + headers[@(header.first.data())] = @(header.second.data()); + } + rlmRequest.headers = headers; + rlmRequest.method = static_cast(request.method); + rlmRequest.timeout = request.timeout_ms / 1000.0; + + // Send the request through to the Cocoa level transport + auto completion_ptr = completion.release(); + [m_transport sendRequestToServer:rlmRequest completion:^(RLMResponse *response) { + util::UniqueFunction completion(completion_ptr); + std::map bridgingHeaders; + [response.headers enumerateKeysAndObjectsUsingBlock:[&](NSString *key, NSString *value, BOOL *) { + bridgingHeaders[key.UTF8String] = value.UTF8String; + }]; + + // Convert the RLMResponse to an app:Response and pass downstream to + // the object store + completion(app::Response{ + .http_status_code = static_cast(response.httpStatusCode), + .custom_status_code = static_cast(response.customStatusCode), + .headers = bridgingHeaders, + .body = response.body ? response.body.UTF8String : "" + }); + }]; + } + + id transport() const { + return m_transport; + } + private: + id m_transport; + }; +} + +#pragma mark RLMAppConfiguration +@implementation RLMAppConfiguration { + realm::app::App::Config _config; + SyncClientConfig _clientConfig; +} + +- (instancetype)init { + if (self = [super init]) { + self.enableSessionMultiplexing = true; + self.encryptMetadata = !getenv("REALM_DISABLE_METADATA_ENCRYPTION") && !RLMIsRunningInPlayground(); + RLMNSStringToStdString(_clientConfig.base_file_path, RLMDefaultDirectoryForBundleIdentifier(nil)); + configureSyncConnectionParameters(_config); + } + return self; +} + +- (instancetype)initWithBaseURL:(nullable NSString *)baseURL + transport:(nullable id)transport + localAppName:(nullable NSString *)localAppName + localAppVersion:(nullable NSString *)localAppVersion { + return [self initWithBaseURL:baseURL + transport:transport + localAppName:localAppName + localAppVersion:localAppVersion + defaultRequestTimeoutMS:60000]; +} + +- (instancetype)initWithBaseURL:(nullable NSString *)baseURL + transport:(nullable id)transport + localAppName:(nullable NSString *)localAppName + localAppVersion:(nullable NSString *)localAppVersion + defaultRequestTimeoutMS:(NSUInteger)defaultRequestTimeoutMS { + if (self = [self init]) { + self.baseURL = baseURL; + self.transport = transport; + self.localAppName = localAppName; + self.localAppVersion = localAppVersion; + self.defaultRequestTimeoutMS = defaultRequestTimeoutMS; + } + return self; +} + +static void configureSyncConnectionParameters(realm::app::App::Config& config) { + // Anonymized BundleId + NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier]; + NSData *bundleIdData = [bundleId dataUsingEncoding:NSUTF8StringEncoding]; + RLMNSStringToStdString(config.device_info.bundle_id, RLMHashBase16Data(bundleIdData.bytes, bundleIdData.length)); + + config.device_info.sdk = "Realm Swift"; + RLMNSStringToStdString(config.device_info.sdk_version, REALM_COCOA_VERSION); + + // Platform info isn't available when running via `swift test`. + // Non-Xcode SPM builds can't build for anything but macOS, so this is + // probably unimportant for now and we can just report "unknown" + auto processInfo = [NSProcessInfo processInfo]; + RLMNSStringToStdString(config.device_info.platform_version, + [processInfo operatingSystemVersionString] ?: @"unknown"); + + RLMNSStringToStdString(config.device_info.framework_version, @__clang_version__); + +#ifdef REALM_UIDEVICE_AVAILABLE + RLMNSStringToStdString(config.device_info.device_name, [UIDevice currentDevice].model); +#endif + struct utsname systemInfo; + uname(&systemInfo); + config.device_info.device_version = systemInfo.machine; +} + +- (const realm::app::App::Config&)config { + if (!_config.transport) { + self.transport = nil; + } + return _config; +} + +- (const realm::SyncClientConfig&)clientConfig { + return _clientConfig; +} + +- (id)copyWithZone:(NSZone *)zone { + RLMAppConfiguration *copy = [[RLMAppConfiguration alloc] init]; + copy->_config = _config; + copy->_clientConfig = _clientConfig; + return copy; +} + +- (NSString *)appId { + return RLMStringViewToNSString(_config.app_id); +} + +- (void)setAppId:(NSString *)appId { + if ([appId length] == 0) { + @throw RLMException(@"AppId cannot be an empty string"); + } + + RLMNSStringToStdString(_config.app_id, appId); +} + +static NSString *getOptionalString(const std::optional& str) { + return str ? RLMStringViewToNSString(*str) : nil; +} + +static void setOptionalString(std::optional& dst, NSString *src) { + if (src.length == 0) { + dst.reset(); + } + else { + dst.emplace(); + RLMNSStringToStdString(*dst, src); + } +} + +- (NSString *)baseURL { + return getOptionalString(_config.base_url); +} + +- (void)setBaseURL:(nullable NSString *)baseURL { + setOptionalString(_config.base_url, baseURL); +} + +- (id)transport { + return static_cast(*_config.transport).transport(); +} + +- (void)setTransport:(id)transport { + if (!transport) { + transport = [RLMNetworkTransport new]; + } + _config.transport = std::make_shared(transport); +} + +- (NSString *)localAppName { + return getOptionalString(_config.local_app_name); +} + +- (void)setLocalAppName:(nullable NSString *)localAppName { + setOptionalString(_config.local_app_name, localAppName); +} + +- (NSString *)localAppVersion { + return getOptionalString(_config.local_app_version); +} + +- (void)setLocalAppVersion:(nullable NSString *)localAppVersion { + setOptionalString(_config.local_app_version, localAppVersion); +} + +- (NSUInteger)defaultRequestTimeoutMS { + return _config.default_request_timeout_ms.value_or(60000U); +} + +- (void)setDefaultRequestTimeoutMS:(NSUInteger)defaultRequestTimeoutMS { + _config.default_request_timeout_ms = (uint64_t)defaultRequestTimeoutMS; +} + +- (BOOL)enableSessionMultiplexing { + return _clientConfig.multiplex_sessions; +} + +- (void)setEnableSessionMultiplexing:(BOOL)enableSessionMultiplexing { + _clientConfig.multiplex_sessions = enableSessionMultiplexing; +} + +- (BOOL)encryptMetadata { + return _clientConfig.metadata_mode == SyncManager::MetadataMode::Encryption; +} + +- (void)setEncryptMetadata:(BOOL)encryptMetadata { + _clientConfig.metadata_mode = encryptMetadata ? SyncManager::MetadataMode::Encryption + : SyncManager::MetadataMode::NoEncryption; +} + +- (NSURL *)rootDirectory { + return [NSURL fileURLWithPath:RLMStringViewToNSString(_clientConfig.base_file_path)]; +} + +- (void)setRootDirectory:(NSURL *)rootDirectory { + RLMNSStringToStdString(_clientConfig.base_file_path, rootDirectory.path); +} + +- (RLMSyncTimeoutOptions *)syncTimeouts { + return [[RLMSyncTimeoutOptions alloc] initWithOptions:_clientConfig.timeouts]; +} + +- (void)setSyncTimeouts:(RLMSyncTimeoutOptions *)syncTimeouts { + _clientConfig.timeouts = syncTimeouts->_options; +} + +@end + +#pragma mark RLMAppSubscriptionToken + +@implementation RLMAppSubscriptionToken { + std::shared_ptr _app; + std::optional _token; +} + +- (instancetype)initWithApp:(std::shared_ptr)app token:(app::App::Token&&)token { + if (self = [super init]) { + _app = std::move(app); + _token = std::move(token); + } + return self; +} + +- (void)unsubscribe { + _token.reset(); + _app.reset(); +} +@end + +#pragma mark RLMApp +@interface RLMApp() { + std::shared_ptr _app; + __weak id _authorizationDelegate API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)); +} + +@end + +@implementation RLMApp : NSObject + ++ (void)initialize { + [RLMRealm class]; + // Even though there is nothing to log when the App initialises, we want to + // be able to log anything happening after this e.g. login/register. + [RLMLogger class]; +} + +- (instancetype)initWithApp:(std::shared_ptr&&)app config:(RLMAppConfiguration *)config { + if (self = [super init]) { + _app = std::move(app); + _configuration = config; + _syncManager = [[RLMSyncManager alloc] initWithSyncManager:_app->sync_manager()]; + } + return self; +} + +- (instancetype)initWithConfiguration:(RLMAppConfiguration *)configuration { + if (self = [super init]) { + _app = RLMTranslateError([&] { + return app::App::get_shared_app(configuration.config, configuration.clientConfig); + }); + _configuration = configuration; + _syncManager = [[RLMSyncManager alloc] initWithSyncManager:_app->sync_manager()]; + } + return self; +} + +static NSMutableDictionary *s_apps = [NSMutableDictionary new]; +static std::mutex& s_appMutex = *new std::mutex(); + ++ (NSArray *)allApps { + std::lock_guard lock(s_appMutex); + return s_apps.allValues; +} + ++ (void)resetAppCache { + std::lock_guard lock(s_appMutex); + [s_apps removeAllObjects]; + app::App::clear_cached_apps(); +} + ++ (instancetype)appWithConfiguration:(RLMAppConfiguration *)configuration { + std::lock_guard lock(s_appMutex); + NSString *appId = configuration.appId; + if (RLMApp *app = s_apps[appId]) { + return app; + } + return s_apps[appId] = [[RLMApp alloc] initWithConfiguration:configuration.copy]; +} + ++ (instancetype)appWithId:(NSString *)appId configuration:(RLMAppConfiguration *)configuration { + std::lock_guard lock(s_appMutex); + if (RLMApp *app = s_apps[appId]) { + return app; + } + configuration = configuration.copy; + configuration.appId = appId; + return s_apps[appId] = [[RLMApp alloc] initWithConfiguration:configuration]; +} + ++ (instancetype)appWithId:(NSString *)appId { + std::lock_guard lock(s_appMutex); + if (RLMApp *app = s_apps[appId]) { + return app; + } + auto config = [[RLMAppConfiguration alloc] init]; + config.appId = appId; + return s_apps[appId] = [[RLMApp alloc] initWithConfiguration:config]; +} + +- (NSString *)appId { + return @(_app->config().app_id.c_str()); +} + +- (std::shared_ptr)_realmApp { + return _app; +} + +- (NSDictionary *)allUsers { + NSMutableDictionary *buffer = [NSMutableDictionary new]; + for (auto&& user : _app->sync_manager()->all_users()) { + NSString *identity = @(user->identity().c_str()); + buffer[identity] = [[RLMUser alloc] initWithUser:std::move(user) app:self]; + } + return buffer; +} + +- (RLMUser *)currentUser { + if (auto user = _app->sync_manager()->get_current_user()) { + return [[RLMUser alloc] initWithUser:user app:self]; + } + return nil; +} + +- (RLMEmailPasswordAuth *)emailPasswordAuth { + return [[RLMEmailPasswordAuth alloc] initWithApp: self]; +} + +- (void)loginWithCredential:(RLMCredentials *)credentials + completion:(RLMUserCompletionBlock)completionHandler { + auto completion = ^(std::shared_ptr user, std::optional error) { + if (error) { + return completionHandler(nil, makeError(*error)); + } + + completionHandler([[RLMUser alloc] initWithUser:user app:self], nil); + }; + return RLMTranslateError([&] { + return _app->log_in_with_credentials(credentials.appCredentials, completion); + }); +} + +- (RLMUser *)switchToUser:(RLMUser *)syncUser { + return RLMTranslateError([&] { + return [[RLMUser alloc] initWithUser:_app->switch_user(syncUser._syncUser) app:self]; + }); +} + +- (RLMPushClient *)pushClientWithServiceName:(NSString *)serviceName { + return RLMTranslateError([&] { + return [[RLMPushClient alloc] initWithPushClient:_app->push_notification_client(serviceName.UTF8String)]; + }); +} + +#pragma mark - Sign In With Apple Extension + +- (void)setAuthorizationDelegate:(id)authorizationDelegate API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + _authorizationDelegate = authorizationDelegate; +} + +- (id)authorizationDelegate API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + return _authorizationDelegate; +} + +- (void)setASAuthorizationControllerDelegateForController:(ASAuthorizationController *)controller API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + controller.delegate = self; +} + +- (void)authorizationController:(__unused ASAuthorizationController *)controller + didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + NSString *jwt = [[NSString alloc] initWithData:((ASAuthorizationAppleIDCredential *)authorization.credential).identityToken + encoding:NSUTF8StringEncoding]; + [self loginWithCredential:[RLMCredentials credentialsWithAppleToken:jwt] + completion:^(RLMUser *user, NSError *error) { + if (user) { + [self.authorizationDelegate authenticationDidCompleteWithUser:user]; + } else { + [self.authorizationDelegate authenticationDidFailWithError:error]; + } + }]; +} + +- (void)authorizationController:(__unused ASAuthorizationController *)controller + didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + [self.authorizationDelegate authenticationDidFailWithError:error]; +} + +- (RLMAppSubscriptionToken *)subscribe:(RLMAppNotificationBlock)block { + return [[RLMAppSubscriptionToken alloc] initWithApp:_app token:_app->subscribe([block, self] (auto&) { + block(self); + })]; +} + +@end diff --git a/Pods/Realm/Realm/RLMArray.mm b/Pods/Realm/Realm/RLMArray.mm new file mode 100644 index 0000000..ae34c64 --- /dev/null +++ b/Pods/Realm/Realm/RLMArray.mm @@ -0,0 +1,629 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMArray_Private.hpp" + +#import "RLMObjectSchema.h" +#import "RLMObjectStore.h" +#import "RLMObject_Private.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMSchema_Private.h" +#import "RLMSwiftSupport.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +@interface RLMArray () +@end + +@implementation RLMArray { + // Backing array when this instance is unmanaged + @public + NSMutableArray *_backingCollection; +} +#pragma mark - Initializers + +- (instancetype)initWithObjectClassName:(__unsafe_unretained NSString *const)objectClassName + keyType:(__unused RLMPropertyType)keyType { + return [self initWithObjectClassName:objectClassName]; +} +- (instancetype)initWithObjectType:(RLMPropertyType)type optional:(BOOL)optional + keyType:(__unused RLMPropertyType)keyType { + return [self initWithObjectType:type optional:optional]; +} + +- (instancetype)initWithObjectClassName:(__unsafe_unretained NSString *const)objectClassName { + REALM_ASSERT([objectClassName length] > 0); + self = [super init]; + if (self) { + _objectClassName = objectClassName; + _type = RLMPropertyTypeObject; + } + return self; +} + +- (instancetype)initWithObjectType:(RLMPropertyType)type optional:(BOOL)optional { + REALM_ASSERT(type != RLMPropertyTypeObject); + self = [super init]; + if (self) { + _type = type; + _optional = optional; + } + return self; +} + +- (void)setParent:(RLMObjectBase *)parentObject property:(RLMProperty *)property { + _parentObject = parentObject; + _key = property.name; + _isLegacyProperty = property.isLegacy; +} + +#pragma mark - Convenience wrappers used for all RLMArray types + +- (void)addObjects:(id)objects { + for (id obj in objects) { + [self addObject:obj]; + } +} + +- (void)addObject:(id)object { + [self insertObject:object atIndex:self.count]; +} + +- (void)removeLastObject { + NSUInteger count = self.count; + if (count) { + [self removeObjectAtIndex:count-1]; + } +} + +- (id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +- (void)setObject:(id)newValue atIndexedSubscript:(NSUInteger)index { + [self replaceObjectAtIndex:index withObject:newValue]; +} + +- (RLMResults *)sortedResultsUsingKeyPath:(NSString *)keyPath ascending:(BOOL)ascending { + return [self sortedResultsUsingDescriptors:@[[RLMSortDescriptor sortDescriptorWithKeyPath:keyPath ascending:ascending]]]; +} + +- (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + NSUInteger index = [self indexOfObjectWhere:predicateFormat args:args]; + va_end(args); + return index; +} + +- (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat args:(va_list)args { + return [self indexOfObjectWithPredicate:[NSPredicate predicateWithFormat:predicateFormat + arguments:args]]; +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block { + return RLMAddNotificationBlock(self, block, nil, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block + keyPaths:(NSArray *)keyPaths { + return RLMAddNotificationBlock(self, block, keyPaths, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, keyPaths, queue); +} +#pragma clang diagnostic pop + +#pragma mark - Unmanaged RLMArray implementation + +- (RLMRealm *)realm { + return nil; +} + +- (id)firstObject { + if (self.count) { + return [self objectAtIndex:0]; + } + return nil; +} + +- (id)lastObject { + NSUInteger count = self.count; + if (count) { + return [self objectAtIndex:count-1]; + } + return nil; +} + +- (id)objectAtIndex:(NSUInteger)index { + validateArrayBounds(self, index); + return [_backingCollection objectAtIndex:index]; +} + +- (NSUInteger)count { + return _backingCollection.count; +} + +- (BOOL)isInvalidated { + return NO; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(__unused NSUInteger)len { + return RLMUnmanagedFastEnumerate(_backingCollection, state); +} + +template +static void changeArray(__unsafe_unretained RLMArray *const ar, + NSKeyValueChange kind, dispatch_block_t f, IndexSetFactory&& is) { + if (!ar->_backingCollection) { + ar->_backingCollection = [NSMutableArray new]; + } + + if (RLMObjectBase *parent = ar->_parentObject) { + NSIndexSet *indexes = is(); + [parent willChange:kind valuesAtIndexes:indexes forKey:ar->_key]; + f(); + [parent didChange:kind valuesAtIndexes:indexes forKey:ar->_key]; + } + else { + f(); + } +} + +static void changeArray(__unsafe_unretained RLMArray *const ar, NSKeyValueChange kind, + NSUInteger index, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return [NSIndexSet indexSetWithIndex:index]; }); +} + +static void changeArray(__unsafe_unretained RLMArray *const ar, NSKeyValueChange kind, + NSRange range, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return [NSIndexSet indexSetWithIndexesInRange:range]; }); +} + +static void changeArray(__unsafe_unretained RLMArray *const ar, NSKeyValueChange kind, + NSIndexSet *is, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return is; }); +} + +void RLMArrayValidateMatchingObjectType(__unsafe_unretained RLMArray *const array, + __unsafe_unretained id const value) { + if (!value && !array->_optional) { + @throw RLMException(@"Invalid nil value for array of '%@'.", + array->_objectClassName ?: RLMTypeToString(array->_type)); + } + if (array->_type != RLMPropertyTypeObject) { + if (!RLMValidateValue(value, array->_type, array->_optional, false, nil)) { + @throw RLMException(@"Invalid value '%@' of type '%@' for expected type '%@%s'.", + value, [value class], RLMTypeToString(array->_type), + array->_optional ? "?" : ""); + } + return; + } + + auto object = RLMDynamicCast(value); + if (!object) { + return; + } + if (!object->_objectSchema) { + @throw RLMException(@"Object cannot be inserted unless the schema is initialized. " + "This can happen if you try to insert objects into a RLMArray / List from a default value or from an overriden unmanaged initializer (`init()`)."); + } + if (![array->_objectClassName isEqualToString:object->_objectSchema.className]) { + @throw RLMException(@"Object of type '%@' does not match RLMArray type '%@'.", + object->_objectSchema.className, array->_objectClassName); + } +} + +static void validateArrayBounds(__unsafe_unretained RLMArray *const ar, + NSUInteger index, bool allowOnePastEnd=false) { + NSUInteger max = ar->_backingCollection.count + allowOnePastEnd; + if (index >= max) { + @throw RLMException(@"Index %llu is out of bounds (must be less than %llu).", + (unsigned long long)index, (unsigned long long)max); + } +} + +- (void)addObjectsFromArray:(NSArray *)array { + for (id obj in array) { + RLMArrayValidateMatchingObjectType(self, obj); + } + changeArray(self, NSKeyValueChangeInsertion, NSMakeRange(_backingCollection.count, array.count), ^{ + [_backingCollection addObjectsFromArray:array]; + }); +} + +- (void)insertObject:(id)anObject atIndex:(NSUInteger)index { + RLMArrayValidateMatchingObjectType(self, anObject); + validateArrayBounds(self, index, true); + changeArray(self, NSKeyValueChangeInsertion, index, ^{ + [_backingCollection insertObject:anObject atIndex:index]; + }); +} + +- (void)insertObjects:(id)objects atIndexes:(NSIndexSet *)indexes { + changeArray(self, NSKeyValueChangeInsertion, indexes, ^{ + NSUInteger currentIndex = [indexes firstIndex]; + for (RLMObject *obj in objects) { + RLMArrayValidateMatchingObjectType(self, obj); + [_backingCollection insertObject:obj atIndex:currentIndex]; + currentIndex = [indexes indexGreaterThanIndex:currentIndex]; + } + }); +} + +- (void)removeObjectAtIndex:(NSUInteger)index { + validateArrayBounds(self, index); + changeArray(self, NSKeyValueChangeRemoval, index, ^{ + [_backingCollection removeObjectAtIndex:index]; + }); +} + +- (void)removeObjectsAtIndexes:(NSIndexSet *)indexes { + changeArray(self, NSKeyValueChangeRemoval, indexes, ^{ + [_backingCollection removeObjectsAtIndexes:indexes]; + }); +} + +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject { + RLMArrayValidateMatchingObjectType(self, anObject); + validateArrayBounds(self, index); + changeArray(self, NSKeyValueChangeReplacement, index, ^{ + [_backingCollection replaceObjectAtIndex:index withObject:anObject]; + }); +} + +- (void)moveObjectAtIndex:(NSUInteger)sourceIndex toIndex:(NSUInteger)destinationIndex { + validateArrayBounds(self, sourceIndex); + validateArrayBounds(self, destinationIndex); + id original = _backingCollection[sourceIndex]; + + auto start = std::min(sourceIndex, destinationIndex); + auto len = std::max(sourceIndex, destinationIndex) - start + 1; + changeArray(self, NSKeyValueChangeReplacement, {start, len}, ^{ + [_backingCollection removeObjectAtIndex:sourceIndex]; + [_backingCollection insertObject:original atIndex:destinationIndex]; + }); +} + +- (void)exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 { + validateArrayBounds(self, index1); + validateArrayBounds(self, index2); + + changeArray(self, NSKeyValueChangeReplacement, ^{ + [_backingCollection exchangeObjectAtIndex:index1 withObjectAtIndex:index2]; + }, [=] { + NSMutableIndexSet *set = [[NSMutableIndexSet alloc] initWithIndex:index1]; + [set addIndex:index2]; + return set; + }); +} + +- (NSUInteger)indexOfObject:(id)object { + RLMArrayValidateMatchingObjectType(self, object); + if (!_backingCollection) { + return NSNotFound; + } + if (_type != RLMPropertyTypeObject) { + return [_backingCollection indexOfObject:object]; + } + + NSUInteger index = 0; + for (RLMObjectBase *cmp in _backingCollection) { + if (RLMObjectBaseAreEqual(object, cmp)) { + return index; + } + index++; + } + return NSNotFound; +} + +- (void)removeAllObjects { + changeArray(self, NSKeyValueChangeRemoval, NSMakeRange(0, _backingCollection.count), ^{ + [_backingCollection removeAllObjects]; + }); +} + +- (void)replaceAllObjectsWithObjects:(NSArray *)objects { + if (_backingCollection.count) { + changeArray(self, NSKeyValueChangeRemoval, NSMakeRange(0, _backingCollection.count), ^{ + [_backingCollection removeAllObjects]; + }); + } + if (![objects respondsToSelector:@selector(count)] || !objects.count) { + return; + } + changeArray(self, NSKeyValueChangeInsertion, NSMakeRange(0, objects.count), ^{ + for (id object in objects) { + [_backingCollection addObject:object]; + } + }); +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsWhere:predicateFormat args:args]; + va_end(args); + return results; +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args { + return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (RLMPropertyType)typeForProperty:(NSString *)propertyName { + if ([propertyName isEqualToString:@"self"]) { + return _type; + } + + RLMObjectSchema *objectSchema; + if (_backingCollection.count) { + objectSchema = [_backingCollection[0] objectSchema]; + } + else { + objectSchema = [RLMSchema.partialPrivateSharedSchema schemaForClassName:_objectClassName]; + } + + return RLMValidatedProperty(objectSchema, propertyName).type; +} + +- (id)aggregateProperty:(NSString *)key operation:(NSString *)op method:(SEL)sel { + // Although delegating to valueForKeyPath: here would allow to support + // nested key paths as well, limiting functionality gives consistency + // between unmanaged and managed arrays. + if ([key rangeOfString:@"."].location != NSNotFound) { + @throw RLMException(@"Nested key paths are not supported yet for KVC collection operators."); + } + + bool allowDate = false; + bool sum = false; + if ([op isEqualToString:@"@min"] || [op isEqualToString:@"@max"]) { + allowDate = true; + } + else if ([op isEqualToString:@"@sum"]) { + sum = true; + } + else if (![op isEqualToString:@"@avg"]) { + // Just delegate to NSArray for all other operators + return [_backingCollection valueForKeyPath:[op stringByAppendingPathExtension:key]]; + } + + RLMPropertyType type = [self typeForProperty:key]; + if (!canAggregate(type, allowDate)) { + NSString *method = sel ? NSStringFromSelector(sel) : op; + if (_type == RLMPropertyTypeObject) { + @throw RLMException(@"%@: is not supported for %@ property '%@.%@'", + method, RLMTypeToString(type), _objectClassName, key); + } + else { + @throw RLMException(@"%@ is not supported for %@%s array", + method, RLMTypeToString(_type), _optional ? "?" : ""); + } + } + + NSArray *values = [key isEqualToString:@"self"] ? _backingCollection : [_backingCollection valueForKey:key]; + if (_optional) { + // Filter out NSNull values to match our behavior on managed arrays + NSIndexSet *nonnull = [values indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger, BOOL *) { + return obj != NSNull.null; + }]; + if (nonnull.count < values.count) { + values = [values objectsAtIndexes:nonnull]; + } + } + id result = [values valueForKeyPath:[op stringByAppendingString:@".self"]]; + return sum && !result ? @0 : result; +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath characterAtIndex:0] != '@') { + return _backingCollection ? [_backingCollection valueForKeyPath:keyPath] : [super valueForKeyPath:keyPath]; + } + + if (!_backingCollection) { + _backingCollection = [NSMutableArray new]; + } + + NSUInteger dot = [keyPath rangeOfString:@"."].location; + if (dot == NSNotFound) { + return [_backingCollection valueForKeyPath:keyPath]; + } + + NSString *op = [keyPath substringToIndex:dot]; + NSString *key = [keyPath substringFromIndex:dot + 1]; + return [self aggregateProperty:key operation:op method:nil]; +} + +- (id)valueForKey:(NSString *)key { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @NO; // Unmanaged arrays are never invalidated + } + if (!_backingCollection) { + _backingCollection = [NSMutableArray new]; + } + return [_backingCollection valueForKey:key]; +} + +- (void)setValue:(id)value forKey:(NSString *)key { + if ([key isEqualToString:@"self"]) { + RLMArrayValidateMatchingObjectType(self, value); + for (NSUInteger i = 0, count = _backingCollection.count; i < count; ++i) { + _backingCollection[i] = value; + } + return; + } + else if (_type == RLMPropertyTypeObject) { + [_backingCollection setValue:value forKey:key]; + } + else { + [self setValue:value forUndefinedKey:key]; + } +} + +- (id)minOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@min" method:_cmd]; +} + +- (id)maxOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@max" method:_cmd]; +} + +- (id)sumOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@sum" method:_cmd]; +} + +- (id)averageOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@avg" method:_cmd]; +} + +- (NSUInteger)indexOfObjectWithPredicate:(NSPredicate *)predicate { + if (!_backingCollection) { + return NSNotFound; + } + return [_backingCollection indexOfObjectPassingTest:^BOOL(id obj, NSUInteger, BOOL *) { + return [predicate evaluateWithObject:obj]; + }]; +} + +- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + if ([indexes indexGreaterThanOrEqualToIndex:self.count] != NSNotFound) { + return nil; + } + return [_backingCollection objectsAtIndexes:indexes] ?: @[]; +} + +- (BOOL)isEqual:(id)object { + if (auto array = RLMDynamicCast(object)) { + if (array.realm) { + return NO; + } + NSArray *otherCollection = array->_backingCollection; + return (_backingCollection.count == 0 && otherCollection.count == 0) + || [_backingCollection isEqual:otherCollection]; + } + return NO; +} + +- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options context:(void *)context { + RLMValidateArrayObservationKey(keyPath, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +#pragma mark - Methods unsupported on unmanaged RLMArray instances + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (RLMSectionedResults *)sectionedResultsSortedUsingKeyPath:(NSString *)keyPath + ascending:(BOOL)ascending + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (RLMSectionedResults *)sectionedResultsUsingSortDescriptors:(NSArray *)sortDescriptors + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (instancetype)freeze { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (instancetype)thaw { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMArray`"); +} + +- (id)objectiveCMetadata { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMArray`"); +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(id)metadata + realm:(RLMRealm *)realm { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMArray`"); +} + +#pragma clang diagnostic pop // unused parameter warning + +#pragma mark - Superclass Overrides + +- (NSString *)description { + return [self descriptionWithMaxDepth:RLMDescriptionMaxDepth]; +} + +- (NSString *)descriptionWithMaxDepth:(NSUInteger)depth { + return RLMDescriptionWithMaxDepth(@"RLMArray", self, depth); +} + +#pragma mark - Key Path Strings + +- (NSString *)propertyKey { + return _key; +} + +@end + +@implementation RLMSortDescriptor + ++ (instancetype)sortDescriptorWithKeyPath:(NSString *)keyPath ascending:(BOOL)ascending { + RLMSortDescriptor *desc = [[RLMSortDescriptor alloc] init]; + desc->_keyPath = keyPath; + desc->_ascending = ascending; + return desc; +} + +- (instancetype)reversedSortDescriptor { + return [self.class sortDescriptorWithKeyPath:_keyPath ascending:!_ascending]; +} + +@end diff --git a/Pods/Realm/Realm/RLMAsymmetricObject.mm b/Pods/Realm/Realm/RLMAsymmetricObject.mm new file mode 100644 index 0000000..d6634a4 --- /dev/null +++ b/Pods/Realm/Realm/RLMAsymmetricObject.mm @@ -0,0 +1,101 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMAsymmetricObject.h" + +#import "RLMObject_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMSchema_Private.h" + +@implementation RLMAsymmetricObject +// synthesized in RLMObjectBase but redeclared here for documentation purposes +@dynamic objectSchema; + +#pragma mark - Designated Initializers + +- (instancetype)init { + return [super init]; +} + +#pragma mark - Convenience Initializers + +- (instancetype)initWithValue:(id)value { + if (!(self = [self init])) { + return nil; + } + RLMInitializeWithValue(self, value, RLMSchema.partialPrivateSharedSchema); + return self; +} + +#pragma mark - Class-based Object Creation + ++ (instancetype)createInRealm:(RLMRealm *)realm withValue:(id)value { + RLMCreateAsymmetricObjectInRealm(realm, [self className], value); + return nil; +} + +#pragma mark - Subscripting + +- (id)objectForKeyedSubscript:(NSString *)key { + return RLMObjectBaseObjectForKeyedSubscript(self, key); +} + +- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key { + RLMObjectBaseSetObjectForKeyedSubscript(self, key, obj); +} + +#pragma mark - Other Instance Methods + ++ (NSString *)className { + return [super className]; +} + +#pragma mark - Default values for schema definition + ++ (NSString *)primaryKey { + return nil; +} + ++ (NSArray *)indexedProperties { + return @[]; +} + ++ (NSDictionary *)linkingObjectsProperties { + return @{}; +} + ++ (NSDictionary *)defaultPropertyValues { + return nil; +} + ++ (NSArray *)ignoredProperties { + return nil; +} + ++ (NSArray *)requiredProperties { + return @[]; +} + ++ (bool)_realmIgnoreClass { + return false; +} + ++ (bool)isAsymmetric { + return true; +} +@end diff --git a/Pods/Realm/Realm/RLMAsyncTask.mm b/Pods/Realm/Realm/RLMAsyncTask.mm new file mode 100644 index 0000000..6c7d0f8 --- /dev/null +++ b/Pods/Realm/Realm/RLMAsyncTask.mm @@ -0,0 +1,476 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2023 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMAsyncTask_Private.h" + +#import "RLMError_Private.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMScheduler.h" +#import "RLMSyncSubscription_Private.h" +#import "RLMUtil.hpp" + +#import +#import +#import +#import + +static dispatch_queue_t s_async_open_queue = dispatch_queue_create("io.realm.asyncOpenDispatchQueue", + DISPATCH_QUEUE_CONCURRENT); +void RLMSetAsyncOpenQueue(dispatch_queue_t queue) { + s_async_open_queue = queue; +} + +static NSError *s_canceledError = [NSError errorWithDomain:NSPOSIXErrorDomain + code:ECANCELED userInfo:@{ + NSLocalizedDescriptionKey: @"Operation canceled" +}]; + +__attribute__((objc_direct_members)) +@implementation RLMAsyncOpenTask { + RLMUnfairMutex _mutex; + std::shared_ptr _task; + std::vector _progressBlocks; + bool _cancel; + + RLMRealmConfiguration *_configuration; + RLMScheduler *_scheduler; + bool _waitForDownloadCompletion; + void (^_completion)(NSError *); + + RLMRealm *_backgroundRealm; +} + +- (void)addProgressNotificationOnQueue:(dispatch_queue_t)queue block:(RLMProgressNotificationBlock)block { + auto wrappedBlock = ^(NSUInteger transferred_bytes, NSUInteger transferrable_bytes) { + dispatch_async(queue, ^{ + @autoreleasepool { + block(transferred_bytes, transferrable_bytes); + } + }); + }; + + std::lock_guard lock(_mutex); + if (_task) { + _task->register_download_progress_notifier(wrappedBlock); + } + else if (!_cancel) { + _progressBlocks.push_back(wrappedBlock); + } +} + +- (void)addProgressNotificationBlock:(RLMProgressNotificationBlock)block { + [self addProgressNotificationOnQueue:dispatch_get_main_queue() block:block]; +} + +- (void)cancel { + std::lock_guard lock(_mutex); + _cancel = true; + _progressBlocks.clear(); + if (_task) { + _task->cancel(); + // Cancelling realm::AsyncOpenTask results in it never calling our callback, + // so if we're currently in that we have to just send the cancellation + // error immediately. In all other cases, though, we want to wait until + // we've actually cancelled and will send the error the next time we + // check for cancellation + [self reportError:s_canceledError]; + } +} + +- (instancetype)initWithConfiguration:(RLMRealmConfiguration *)configuration + confinedTo:(RLMScheduler *)scheduler + download:(bool)waitForDownloadCompletion { + if (!(self = [super init])) { + return self; + } + + // Copying the configuration here as the user could potentially modify + // the config after calling async open + _configuration = configuration.copy; + _scheduler = scheduler; + _waitForDownloadCompletion = waitForDownloadCompletion; + + return self; +} + +- (instancetype)initWithConfiguration:(RLMRealmConfiguration *)configuration + confinedTo:(RLMScheduler *)confinement + download:(bool)waitForDownloadCompletion + completion:(RLMAsyncOpenRealmCallback)completion { + self = [self initWithConfiguration:configuration confinedTo:confinement + download:waitForDownloadCompletion]; + [self waitForOpen:completion]; + return self; +} + +- (void)waitForOpen:(RLMAsyncOpenRealmCallback)completion { + __weak auto weakSelf = self; + [self waitWithCompletion:^(NSError *error) { + RLMRealm *realm; + if (auto self = weakSelf) { + realm = self->_localRealm; + self->_localRealm = nil; + } + completion(realm, error); + }]; +} + +- (void)waitWithCompletion:(void (^)(NSError *))completion { + std::lock_guard lock(_mutex); + _completion = completion; + if (_cancel) { + return [self reportError:s_canceledError]; + } + + // get_synchronized_realm() synchronously opens the DB and performs file-format + // upgrades, so we want to dispatch to the background before invoking it. + dispatch_async(s_async_open_queue, ^{ + @autoreleasepool { + [self startAsyncOpen]; + } + }); +} + +// The full async open flow is: +// 1. Dispatch to a background queue +// 2. Use Realm::get_synchronized_realm() to create the Realm file, run +// migrations and compactions, and download the latest data from the server. +// 3. Dispatch back to queue +// 4. Initialize a RLMRealm in the background queue to perform the SDK +// initialization (e.g. creating managed accessor classes). +// 5. Wait for initial flexible sync subscriptions to complete +// 6. Dispatch to the final scheduler +// 7. Open the final RLMRealm, release the previously opened background one, +// and then invoke the completion callback. +// +// Steps 2 and 5 are skipped for non-sync or non-flexible sync Realms, in which +// case step 4 will handle doing migrations and compactions etc. in the background. +// +// At any point `cancel` can be called from another thread. Cancellation is mostly +// cooperative rather than preemptive: we check at each step if we've been cancelled, +// and if so call the completion with the cancellation error rather than +// proceeding. Downloading the data from the server is the one exception to this. +// Ideally waiting for flexible sync subscriptions would also be preempted. +- (void)startAsyncOpen { + std::unique_lock lock(_mutex); + if ([self checkCancellation]) { + return; + } + + if (_waitForDownloadCompletion && _configuration.configRef.sync_config) { +#if REALM_ENABLE_SYNC + _task = realm::Realm::get_synchronized_realm(_configuration.config); + for (auto& block : _progressBlocks) { + _task->register_download_progress_notifier(block); + } + _progressBlocks.clear(); + _task->start([=](realm::ThreadSafeReference ref, std::exception_ptr err) { + std::lock_guard lock(_mutex); + if ([self checkCancellation]) { + return; + } + // Note that cancellation intentionally trumps reporting other kinds + // of errors + if (err) { + return [self reportException:err]; + } + + // Dispatch blocks can only capture copyable types, so we need to + // resolve the TSR to a shared_ptr + auto realm = ref.resolve>(nullptr); + // We're now running on the sync worker thread, so hop back + // to a more appropriate queue for the next stage of init. + dispatch_async(s_async_open_queue, ^{ + @autoreleasepool { + [self downloadCompleted]; + // Capture the Realm to keep the RealmCoordinator alive + // so that we don't have to reopen it. + static_cast(realm); + } + }); + }); +#else + @throw RLMException(@"Realm was not built with sync enabled"); +#endif + } + else { + // We're not downloading first, so just proceed directly to the next step. + lock.unlock(); + [self downloadCompleted]; + } +} + +- (void)downloadCompleted { + std::unique_lock lock(_mutex); + _task.reset(); + if ([self checkCancellation]) { + return; + } + + NSError *error; + // We've now downloaded all data (if applicable) and done the object + // store initialization, and are back on our background queue. Next we + // want to do our own initialization while still in the background + @autoreleasepool { + // Holding onto the Realm so that opening the final Realm on the target + // scheduler can hit the fast path + _backgroundRealm = [RLMRealm realmWithConfiguration:_configuration + confinedTo:RLMScheduler.currentRunLoop error:&error]; + if (error) { + return [self reportError:error]; + } + } + +#if REALM_ENABLE_SYNC + // If we're opening a flexible sync Realm, we now want to wait for the + // initial subscriptions to be ready + if (_waitForDownloadCompletion && _backgroundRealm.isFlexibleSync) { + auto subscriptions = _backgroundRealm.subscriptions; + if (subscriptions.state == RLMSyncSubscriptionStatePending) { + // FIXME: need cancellation for waiting for the subscription + return [subscriptions waitForSynchronizationOnQueue:nil + completionBlock:^(NSError *error) { + if (error) { + std::lock_guard lock(_mutex); + return [self reportError:error]; + } + [self asyncOpenCompleted]; + }]; + } + } +#endif + lock.unlock(); + [self asyncOpenCompleted]; +} + +- (void)asyncOpenCompleted { + std::lock_guard lock(_mutex); + if (![self checkCancellation]) { + [_scheduler invoke:^{ + [self openFinalRealmAndCallCompletion]; + }]; + } +} + +- (void)openFinalRealmAndCallCompletion { + std::unique_lock lock(_mutex); + @autoreleasepool { + if ([self checkCancellation]) { + return; + } + if (!_completion) { + return; + } + NSError *error; + auto completion = _completion; + // It should not actually be possible for this to fail + _localRealm = [RLMRealm realmWithConfiguration:_configuration + confinedTo:_scheduler + error:&error]; + [self releaseResources]; + + lock.unlock(); + completion(error); + } +} + +- (bool)checkCancellation { + if (_cancel && _completion) { + [self reportError:s_canceledError]; + } + return _cancel; +} + +- (void)reportException:(std::exception_ptr const&)err { + try { + std::rethrow_exception(err); + } + catch (realm::Exception const& e) { + if (e.code() == realm::ErrorCodes::OperationAborted) { + return [self reportError:s_canceledError]; + } + [self reportError:makeError(e)]; + } + catch (...) { + NSError *error; + RLMRealmTranslateException(&error); + [self reportError:error]; + } +} + +- (void)reportError:(NSError *)error { + if (!_completion || !_scheduler) { + return; + } + + auto completion = _completion; + auto scheduler = _scheduler; + [self releaseResources]; + [scheduler invoke:^{ + completion(error); + }]; +} + +- (void)releaseResources { + _backgroundRealm = nil; + _configuration = nil; + _scheduler = nil; + _completion = nil; +} +@end + +@implementation RLMAsyncDownloadTask { + RLMUnfairMutex _mutex; + std::shared_ptr _session; + bool _started; +} + +- (instancetype)initWithRealm:(RLMRealm *)realm { + if (self = [super init]) { + _session = realm->_realm->sync_session(); + } + return self; +} + +- (void)waitWithCompletion:(void (^)(NSError *_Nullable))completion { + std::unique_lock lock(_mutex); + if (!_session) { + lock.unlock(); + return completion(nil); + } + + _started = true; + _session->revive_if_needed(); + _session->wait_for_download_completion([=](realm::Status status) { + completion(makeError(status)); + }); +} + +- (void)cancel { + std::unique_lock lock(_mutex); + if (_started) { + _session->force_close(); + } + _session = nullptr; +} +@end + +__attribute__((objc_direct_members)) +@implementation RLMAsyncRefreshTask { + RLMUnfairMutex _mutex; + void (^_completion)(bool); + bool _complete; + bool _didRefresh; +} + +- (void)complete:(bool)didRefresh { + void (^completion)(bool); + { + std::lock_guard lock(_mutex); + std::swap(completion, _completion); + _complete = true; + // If we're both cancelled and did complete a refresh then continue + // to report true + _didRefresh = _didRefresh || didRefresh; + } + if (completion) { + completion(didRefresh); + } +} + +- (void)wait:(void (^)(bool))completion { + bool didRefresh; + { + std::lock_guard lock(_mutex); + if (!_complete) { + _completion = completion; + return; + } + didRefresh = _didRefresh; + } + completion(didRefresh); +} + ++ (RLMAsyncRefreshTask *)completedRefresh { + static RLMAsyncRefreshTask *shared = [] { + auto refresh = [[RLMAsyncRefreshTask alloc] init]; + refresh->_complete = true; + refresh->_didRefresh = true; + return refresh; + }(); + return shared; +} +@end + +@implementation RLMAsyncWriteTask { + // Mutex guards _realm and _completion + RLMUnfairMutex _mutex; + + // _realm is non-nil only while waiting for an async write to begin. It is + // set to `nil` when it either completes or is cancelled. + RLMRealm *_realm; + dispatch_block_t _completion; + + RLMAsyncTransactionId _id; +} + +// No locking needed for these two as they have to be called before the +// cancellation handler is set up +- (instancetype)initWithRealm:(RLMRealm *)realm { + if (self = [super init]) { + _realm = realm; + } + return self; +} +- (void)setTransactionId:(RLMAsyncTransactionId)transactionID { + _id = transactionID; +} + +- (void)complete:(bool)cancel { + // The swap-under-lock pattern is used to avoid invoking the callback with + // a lock held + dispatch_block_t completion; + { + std::lock_guard lock(_mutex); + std::swap(completion, _completion); + if (cancel) { + // This is a no-op if cancellation is coming after the wait completed + [_realm cancelAsyncTransaction:_id]; + } + _realm = nil; + } + if (completion) { + completion(); + } +} + +- (void)wait:(void (^)())completion { + { + std::lock_guard lock(_mutex); + // `_realm` being non-nil means it's neither completed nor been cancelled + if (_realm) { + _completion = completion; + return; + } + } + + // It has either been completed or cancelled, so call the callback immediately + completion(); +} +@end diff --git a/Pods/Realm/Realm/RLMBSON.mm b/Pods/Realm/Realm/RLMBSON.mm new file mode 100644 index 0000000..c6c49a6 --- /dev/null +++ b/Pods/Realm/Realm/RLMBSON.mm @@ -0,0 +1,423 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMBSON_Private.hpp" + +#import "RLMDecimal128_Private.hpp" +#import "RLMObjectId_Private.hpp" +#import "RLMUUID_Private.hpp" +#import "RLMUtil.hpp" + +#import + +using namespace realm; +using namespace bson; + +#pragma mark NSNull + +@implementation NSNull (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeNull; +} + +@end + +#pragma mark RLMObjectId + +@implementation RLMObjectId (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeObjectId; +} + +@end + +#pragma mark RLMDecimal128 + +@implementation RLMDecimal128 (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeDecimal128; +} + +@end + +#pragma mark NSString + +@implementation NSString (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeString; +} + +@end + +#pragma mark NSNumber + +@implementation NSNumber (RLMBSON) + +- (RLMBSONType)bsonType { + char numberType = [self objCType][0]; + + if (numberType == *@encode(bool) || + numberType == *@encode(char)) { + return RLMBSONTypeBool; + } else if (numberType == *@encode(int) || + numberType == *@encode(short) || + numberType == *@encode(unsigned short) || + numberType == *@encode(unsigned int)) { + return RLMBSONTypeInt32; + } else if (numberType == *@encode(long) || + numberType == *@encode(long long) || + numberType == *@encode(unsigned long) || + numberType == *@encode(unsigned long long)) { + return RLMBSONTypeInt64; + } else { + return RLMBSONTypeDouble; + } +} + +@end + +#pragma mark NSMutableArray + +@implementation NSMutableArray (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeArray; +} + +- (instancetype)initWithBsonArray:(BsonArray)bsonArray { + + if ((self = [self init])) { + for (auto& entry : bsonArray) { + [self addObject:RLMConvertBsonToRLMBSON(entry)]; + } + + return self; + } + + return nil; +} + +@end + +@implementation NSArray (RLMBSON) + +- (BsonArray)bsonArrayValue { + BsonArray bsonArray; + for (id value in self) { + bsonArray.push_back(RLMConvertRLMBSONToBson(value)); + } + return bsonArray; +} + +- (RLMBSONType)bsonType { + return RLMBSONTypeArray; +} + +@end + +#pragma mark NSDictionary + +@implementation NSMutableDictionary (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeDocument; +} + +- (BsonDocument)bsonDocumentValue { + BsonDocument bsonDocument; + for (NSString *value in self) { + bsonDocument[value.UTF8String] = RLMConvertRLMBSONToBson(self[value]); + } + return bsonDocument; +} + +- (instancetype)initWithBsonDocument:(BsonDocument)bsonDocument { + if ((self = [self init])) { + for (auto it = bsonDocument.begin(); it != bsonDocument.end(); ++it) { + const auto& entry = (*it); + [self setObject:RLMConvertBsonToRLMBSON(entry.second) forKey:@(entry.first.data())]; + } + + return self; + } + + return nil; +} + +@end + +@implementation NSDictionary (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeDocument; +} + +- (BsonDocument)bsonDocumentValue { + BsonDocument bsonDocument; + for (NSString *value in self) { + bsonDocument[value.UTF8String] = RLMConvertRLMBSONToBson(self[value]); + } + return bsonDocument; +} + +@end + +#pragma mark NSData + +@implementation NSData (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeBinary; +} + +- (instancetype)initWithBsonBinary:(std::vector)bsonBinary { + if ((self = [NSData dataWithBytes:bsonBinary.data() length:bsonBinary.size()])) { + return self; + } + + return nil; +} + +@end + +#pragma mark NSDate + +@implementation NSDate (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeDatetime; +} + +@end + +#pragma mark NSUUID + +@implementation NSUUID (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeUUID; +} + +@end + +#pragma mark NSRegularExpression + +@implementation NSRegularExpression (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeRegularExpression; +} + +- (RegularExpression)regularExpressionValue { + using Option = RegularExpression::Option; + std::string s; + + if ((_options & NSRegularExpressionCaseInsensitive) != 0) s += 'i'; + if ((_options & NSRegularExpressionUseUnixLineSeparators) != 0) s += 'm'; + if ((_options & NSRegularExpressionDotMatchesLineSeparators) != 0) s += 's'; + if ((_options & NSRegularExpressionUseUnicodeWordBoundaries) != 0) s += 'x'; + + return RegularExpression(_pattern.UTF8String, s); +} + +- (instancetype)initWithRegularExpression:(RegularExpression)regularExpression { + if ((self = [self init])) { + _pattern = @(regularExpression.pattern().data()); + switch (regularExpression.options()) { + case realm::bson::RegularExpression::Option::None: + _options = 0; + break; + case realm::bson::RegularExpression::Option::IgnoreCase: + _options = NSRegularExpressionCaseInsensitive; + break; + case realm::bson::RegularExpression::Option::Multiline: + _options = NSRegularExpressionUseUnixLineSeparators; + break; + case realm::bson::RegularExpression::Option::Dotall: + _options = NSRegularExpressionDotMatchesLineSeparators; + break; + case realm::bson::RegularExpression::Option::Extended: + _options = NSRegularExpressionUseUnicodeWordBoundaries; + break; + } + return self; + } + + return nil; +} + +@end + +#pragma mark RLMMaxKey + +@implementation RLMMaxKey + +- (BOOL)isEqual:(id)other { + return other == self || ([other class] == [self class]); +} + +- (NSUInteger)hash { + return 0; +} + +@end + +#pragma mark RLMMaxKey + +@implementation RLMMinKey + +- (BOOL)isEqual:(id)other { + return other == self || ([other class] == [self class]); +} + +- (NSUInteger)hash { + return 0; +} + +@end + +@implementation RLMMaxKey (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeMaxKey; +} + +@end + +@implementation RLMMinKey (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeMinKey; +} + +@end + +#pragma mark RLMBSONToBson + +Bson RLMConvertRLMBSONToBson(id b) { + switch ([b bsonType]) { + case RLMBSONTypeString: + return ((NSString *)b).UTF8String; + case RLMBSONTypeInt32: + return ((NSNumber *)b).intValue; + case RLMBSONTypeInt64: + return ((NSNumber *)b).longLongValue; + case RLMBSONTypeObjectId: + return [((RLMObjectId *)b) value]; + case RLMBSONTypeNull: + return util::none; + case RLMBSONTypeBool: + return (bool)((NSNumber *)b).boolValue; + case RLMBSONTypeDouble: + return ((NSNumber *)b).doubleValue; + case RLMBSONTypeBinary: + return std::vector((char*)((NSData *)b).bytes, + ((char*)((NSData *)b).bytes) + (int)((NSData *)b).length); + case RLMBSONTypeTimestamp: + // This represents a value of `Timestamp` in a MongoDB Collection. + return MongoTimestamp(((NSDate *)b).timeIntervalSince1970, 0); + case RLMBSONTypeDatetime: + // This represents a value of `Date` in a MongoDB Collection. + return RLMTimestampForNSDate((NSDate *)b); + case RLMBSONTypeDecimal128: + return [((RLMDecimal128 *)b) decimal128Value]; + case RLMBSONTypeRegularExpression: + return [((NSRegularExpression *)b) regularExpressionValue]; + case RLMBSONTypeMaxKey: + return max_key; + case RLMBSONTypeMinKey: + return min_key; + case RLMBSONTypeDocument: + return [((NSDictionary *)b) bsonDocumentValue]; + case RLMBSONTypeArray: + return [((NSArray *)b) bsonArrayValue]; + case RLMBSONTypeUUID: + return [((NSUUID *)b) rlm_uuidValue]; + } +} + +BsonDocument RLMConvertRLMBSONArrayToBsonDocument(NSArray> *array) { + BsonDocument bsonDocument = BsonDocument{}; + for (NSDictionary> *item in array) { + [item enumerateKeysAndObjectsUsingBlock:[&](NSString *key, id bson, BOOL *) { + bsonDocument[key.UTF8String] = RLMConvertRLMBSONToBson(bson); + }]; + } + return bsonDocument; +} + +#pragma mark BsonToRLMBSON + +id RLMConvertBsonToRLMBSON(const Bson& b) { + switch (b.type()) { + case realm::bson::Bson::Type::Null: + return [NSNull null]; + case realm::bson::Bson::Type::Int32: + return @(static_cast(b)); + case realm::bson::Bson::Type::Int64: + return @(static_cast(b)); + case realm::bson::Bson::Type::Bool: + return @(static_cast(b)); + case realm::bson::Bson::Type::Double: + return @(static_cast(b)); + case realm::bson::Bson::Type::String: + return @(static_cast(b).c_str()); + case realm::bson::Bson::Type::Binary: + return [[NSData alloc] initWithBsonBinary:static_cast>(b)]; + case realm::bson::Bson::Type::Timestamp: + return [[NSDate alloc] initWithTimeIntervalSince1970:static_cast(b).seconds]; + case realm::bson::Bson::Type::Datetime: + return [[NSDate alloc] initWithTimeIntervalSince1970:static_cast(b).get_seconds()]; + case realm::bson::Bson::Type::ObjectId: + return [[RLMObjectId alloc] initWithValue:static_cast(b)]; + case realm::bson::Bson::Type::Decimal128: + return [[RLMDecimal128 alloc] initWithDecimal128:static_cast(b)]; + case realm::bson::Bson::Type::RegularExpression: + return [[NSRegularExpression alloc] initWithRegularExpression:static_cast(b)]; + case realm::bson::Bson::Type::MaxKey: + return [RLMMaxKey new]; + case realm::bson::Bson::Type::MinKey: + return [RLMMinKey new]; + case realm::bson::Bson::Type::Document: + return [[NSMutableDictionary alloc] initWithBsonDocument:static_cast(b)]; + case realm::bson::Bson::Type::Array: + return [[NSMutableArray alloc] initWithBsonArray:static_cast(b)]; + case realm::bson::Bson::Type::Uuid: + return [[NSUUID alloc] initWithRealmUUID:static_cast(b)]; + } + return nil; +} + +id RLMConvertBsonDocumentToRLMBSON(std::optional b) { + return b ? RLMConvertBsonToRLMBSON(*b) : nil; +} + +NSArray> *RLMConvertBsonDocumentToRLMBSONArray(std::optional b) { + if (!b) { + return @[]; + } + NSMutableArray> *array = [[NSMutableArray alloc] init]; + for (const auto& [key, value] : *b) { + [array addObject:@{@(key.c_str()): RLMConvertBsonToRLMBSON(value)}]; + } + return array; +} diff --git a/Pods/Realm/Realm/RLMClassInfo.mm b/Pods/Realm/Realm/RLMClassInfo.mm new file mode 100644 index 0000000..a9dff94 --- /dev/null +++ b/Pods/Realm/Realm/RLMClassInfo.mm @@ -0,0 +1,229 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMClassInfo.hpp" + +#import "RLMRealm_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMSchema.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import +#import +#import + +using namespace realm; + +RLMClassInfo::RLMClassInfo(__unsafe_unretained RLMRealm *const realm, + __unsafe_unretained RLMObjectSchema *const rlmObjectSchema, + const realm::ObjectSchema *objectSchema) +: realm(realm), rlmObjectSchema(rlmObjectSchema), objectSchema(objectSchema) { } + +RLMClassInfo::RLMClassInfo(RLMRealm *realm, RLMObjectSchema *rlmObjectSchema, + std::unique_ptr schema) +: realm(realm) +, rlmObjectSchema(rlmObjectSchema) +, objectSchema(&*schema) +, dynamicObjectSchema(std::move(schema)) +, dynamicRLMObjectSchema(rlmObjectSchema) +{ } + +realm::TableRef RLMClassInfo::table() const { + if (auto key = objectSchema->table_key) { + return realm.group.get_table(objectSchema->table_key); + } + return nullptr; +} + +RLMProperty *RLMClassInfo::propertyForTableColumn(ColKey col) const noexcept { + auto const& props = objectSchema->persisted_properties; + for (size_t i = 0; i < props.size(); ++i) { + if (props[i].column_key == col) { + return rlmObjectSchema.properties[i]; + } + } + return nil; +} + +RLMProperty *RLMClassInfo::propertyForPrimaryKey() const noexcept { + return rlmObjectSchema.primaryKeyProperty; +} + +realm::ColKey RLMClassInfo::tableColumn(NSString *propertyName) const { + return tableColumn(RLMValidatedProperty(rlmObjectSchema, propertyName)); +} + +realm::ColKey RLMClassInfo::tableColumn(RLMProperty *property) const { + return objectSchema->persisted_properties[property.index].column_key; +} + +realm::ColKey RLMClassInfo::computedTableColumn(RLMProperty *property) const { + // Retrieve the table key and class info for the origin property + // that corresponds to the target property. + RLMClassInfo& originInfo = realm->_info[property.objectClassName]; + TableKey originTableKey = originInfo.objectSchema->table_key; + + TableRef originTable = realm.group.get_table(originTableKey); + // Get the column key for origin's forward link that links to the property on the target. + ColKey forwardLinkKey = originInfo.tableColumn(property.linkOriginPropertyName); + + // The column key opposite of the origin's forward link is the target's backlink property. + return originTable->get_opposite_column(forwardLinkKey); +} + +RLMClassInfo &RLMClassInfo::linkTargetType(size_t propertyIndex) { + return realm->_info[rlmObjectSchema.properties[propertyIndex].objectClassName]; +} + +RLMClassInfo &RLMClassInfo::linkTargetType(realm::Property const& property) { + REALM_ASSERT(property.type == PropertyType::Object); + return linkTargetType(&property - &objectSchema->persisted_properties[0]); +} + +RLMClassInfo &RLMClassInfo::resolve(__unsafe_unretained RLMRealm *const realm) { + return realm->_info[rlmObjectSchema.className]; +} + +bool RLMClassInfo::isSwiftClass() const noexcept { + return rlmObjectSchema.isSwiftClass; +} + +bool RLMClassInfo::isDynamic() const noexcept { + return !!dynamicObjectSchema; +} + +static KeyPath keyPathFromString(RLMRealm *realm, + RLMSchema *schema, + const RLMClassInfo *info, + RLMObjectSchema *rlmObjectSchema, + NSString *keyPath) { + KeyPath keyPairs; + + for (NSString *component in [keyPath componentsSeparatedByString:@"."]) { + RLMProperty *property = rlmObjectSchema[component]; + if (!property) { + throw RLMException(@"Invalid property name: property '%@' not found in object of type '%@'", + component, rlmObjectSchema.className); + } + + TableKey tk = info->objectSchema->table_key; + ColKey ck; + if (property.type == RLMPropertyTypeObject) { + ck = info->tableColumn(property.name); + info = &realm->_info[property.objectClassName]; + rlmObjectSchema = schema[property.objectClassName]; + } else if (property.type == RLMPropertyTypeLinkingObjects) { + ck = info->computedTableColumn(property); + info = &realm->_info[property.objectClassName]; + rlmObjectSchema = schema[property.objectClassName]; + } else { + ck = info->tableColumn(property.name); + } + + keyPairs.emplace_back(tk, ck); + } + return keyPairs; +} + +std::optional RLMClassInfo::keyPathArrayFromStringArray(NSArray *keyPaths) const { + std::optional keyPathArray; + if (keyPaths.count) { + keyPathArray.emplace(); + for (NSString *keyPath in keyPaths) { + keyPathArray->push_back(keyPathFromString(realm, realm.schema, this, + rlmObjectSchema, keyPath)); + } + } + return keyPathArray; +} + +RLMSchemaInfo::impl::iterator RLMSchemaInfo::begin() noexcept { return m_objects.begin(); } +RLMSchemaInfo::impl::iterator RLMSchemaInfo::end() noexcept { return m_objects.end(); } +RLMSchemaInfo::impl::const_iterator RLMSchemaInfo::begin() const noexcept { return m_objects.begin(); } +RLMSchemaInfo::impl::const_iterator RLMSchemaInfo::end() const noexcept { return m_objects.end(); } + +RLMClassInfo& RLMSchemaInfo::operator[](NSString *name) { + auto it = m_objects.find(name); + if (it == m_objects.end()) { + @throw RLMException(@"Object type '%@' is not managed by the Realm. " + @"If using a custom `objectClasses` / `objectTypes` array in your configuration, " + @"add `%@` to the list of `objectClasses` / `objectTypes`.", + name, name); + } + return *&it->second; +} + +RLMClassInfo* RLMSchemaInfo::operator[](realm::TableKey key) { + for (auto& [name, info] : m_objects) { + if (info.objectSchema->table_key == key) + return &info; + } + return nullptr; +} + +RLMSchemaInfo::RLMSchemaInfo(RLMRealm *realm) { + RLMSchema *rlmSchema = realm.schema; + realm::Schema const& schema = realm->_realm->schema(); + // rlmSchema can be larger due to multiple classes backed by one table + REALM_ASSERT(rlmSchema.objectSchema.count >= schema.size()); + + m_objects.reserve(schema.size()); + for (RLMObjectSchema *rlmObjectSchema in rlmSchema.objectSchema) { + auto it = schema.find(rlmObjectSchema.objectStoreName); + if (it == schema.end()) { + continue; + } + m_objects.emplace(std::piecewise_construct, + std::forward_as_tuple(rlmObjectSchema.className), + std::forward_as_tuple(realm, rlmObjectSchema, + &*it)); + } +} + +RLMSchemaInfo RLMSchemaInfo::clone(realm::Schema const& source_schema, + __unsafe_unretained RLMRealm *const target_realm) { + RLMSchemaInfo info; + info.m_objects.reserve(m_objects.size()); + + auto& schema = target_realm->_realm->schema(); + REALM_ASSERT_DEBUG(schema == source_schema); + for (auto& [name, class_info] : m_objects) { + if (class_info.isDynamic()) { + continue; + } + size_t idx = class_info.objectSchema - &*source_schema.begin(); + info.m_objects.emplace(std::piecewise_construct, + std::forward_as_tuple(name), + std::forward_as_tuple(target_realm, class_info.rlmObjectSchema, + &*schema.begin() + idx)); + } + return info; +} + +void RLMSchemaInfo::appendDynamicObjectSchema(std::unique_ptr schema, + RLMObjectSchema *objectSchema, + __unsafe_unretained RLMRealm *const target_realm) { + m_objects.emplace(std::piecewise_construct, + std::forward_as_tuple(objectSchema.className), + std::forward_as_tuple(target_realm, objectSchema, + std::move(schema))); +} diff --git a/Pods/Realm/Realm/RLMCollection.mm b/Pods/Realm/Realm/RLMCollection.mm new file mode 100644 index 0000000..aebaf1e --- /dev/null +++ b/Pods/Realm/Realm/RLMCollection.mm @@ -0,0 +1,541 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMCollection_Private.hpp" + +#import "RLMAccessor.hpp" +#import "RLMArray_Private.hpp" +#import "RLMDictionary_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftCollectionBase.h" + +#import +#import +#import +#import + +static const int RLMEnumerationBufferSize = 16; + +@implementation RLMFastEnumerator { + // The buffer supplied by fast enumeration does not retain the objects given + // to it, but because we create objects on-demand and don't want them + // autoreleased (a table can have more rows than the device has memory for + // accessor objects) we need a thing to retain them. + id _strongBuffer[RLMEnumerationBufferSize]; + + RLMRealm *_realm; + RLMClassInfo *_info; + + // A pointer to either _snapshot or a Results from the source collection, + // to avoid having to copy the Results when not in a write transaction + realm::Results *_results; + realm::Results _snapshot; + + // A strong reference to the collection being enumerated to ensure it stays + // alive when we're holding a pointer to a member in it + id _collection; +} + +- (instancetype)initWithBackingCollection:(realm::object_store::Collection const&)backingCollection + collection:(id)collection + classInfo:(RLMClassInfo&)info { + self = [super init]; + if (self) { + _info = &info; + _realm = _info->realm; + + if (_realm.inWriteTransaction) { + _snapshot = backingCollection.as_results().snapshot(); + } + else { + _snapshot = backingCollection.as_results(); + _collection = collection; + [_realm registerEnumerator:self]; + } + _results = &_snapshot; + } + return self; +} + +- (instancetype)initWithBackingDictionary:(realm::object_store::Dictionary const&)backingDictionary + dictionary:(RLMManagedDictionary *)dictionary + classInfo:(RLMClassInfo&)info { + self = [super init]; + if (self) { + _info = &info; + _realm = _info->realm; + + if (_realm.inWriteTransaction) { + _snapshot = backingDictionary.get_keys().snapshot(); + } + else { + _snapshot = backingDictionary.get_keys(); + _collection = dictionary; + [_realm registerEnumerator:self]; + } + _results = &_snapshot; + } + return self; +} + +- (instancetype)initWithResults:(realm::Results&)results + collection:(id)collection + classInfo:(RLMClassInfo&)info { + self = [super init]; + if (self) { + _info = &info; + _realm = _info->realm; + if (_realm.inWriteTransaction) { + _snapshot = results.snapshot(); + _results = &_snapshot; + } + else { + _results = &results; + _collection = collection; + [_realm registerEnumerator:self]; + } + } + return self; +} + +- (void)dealloc { + if (_collection) { + [_realm unregisterEnumerator:self]; + } +} + +- (void)detach { + _snapshot = _results->snapshot(); + _results = &_snapshot; + _collection = nil; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + count:(NSUInteger)len { + [_realm verifyThread]; + if (!_results->is_valid()) { + @throw RLMException(@"Collection is no longer valid"); + } + // The fast enumeration buffer size is currently a hardcoded number in the + // compiler so this can't actually happen, but just in case it changes in + // the future... + if (len > RLMEnumerationBufferSize) { + len = RLMEnumerationBufferSize; + } + + NSUInteger batchCount = 0, count = state->extra[1]; + + @autoreleasepool { + RLMAccessorContext ctx(*_info); + for (NSUInteger index = state->state; index < count && batchCount < len; ++index) { + _strongBuffer[batchCount] = _results->get(ctx, index); + batchCount++; + } + } + + for (NSUInteger i = batchCount; i < len; ++i) { + _strongBuffer[i] = nil; + } + + if (batchCount == 0) { + // Release our data if we're done, as we're autoreleased and so may + // stick around for a while + if (_collection) { + _collection = nil; + [_realm unregisterEnumerator:self]; + } + + _snapshot = {}; + } + + state->itemsPtr = (__unsafe_unretained id *)(void *)_strongBuffer; + state->state += batchCount; + state->mutationsPtr = state->extra+1; + + return batchCount; +} +@end + +NSUInteger RLMFastEnumerate(NSFastEnumerationState *state, + NSUInteger len, + id collection) { + __autoreleasing RLMFastEnumerator *enumerator; + if (state->state == 0) { + enumerator = collection.fastEnumerator; + state->extra[0] = (long)enumerator; + state->extra[1] = collection.count; + } + else { + enumerator = (__bridge id)(void *)state->extra[0]; + } + + return [enumerator countByEnumeratingWithState:state count:len]; +} + +@interface RLMArrayHolder : NSObject +@end +@implementation RLMArrayHolder { + std::unique_ptr items; +} + +NSUInteger RLMUnmanagedFastEnumerate(id collection, NSFastEnumerationState *state) { + if (state->state != 0) { + return 0; + } + + // We need to enumerate a copy of the backing array so that it doesn't + // reflect changes made during enumeration. This copy has to be autoreleased + // (since there's nowhere for us to store a strong reference), and uses + // RLMArrayHolder rather than an NSArray because NSArray doesn't guarantee + // that it'll use a single contiguous block of memory, and if it doesn't + // we'd need to forward multiple calls to this method to the same NSArray, + // which would require holding a reference to it somewhere. + __autoreleasing RLMArrayHolder *copy = [[RLMArrayHolder alloc] init]; + copy->items = std::make_unique([collection count]); + + NSUInteger i = 0; + for (id object in collection) { + copy->items[i++] = object; + } + + state->itemsPtr = (__unsafe_unretained id *)(void *)copy->items.get(); + // needs to point to something valid, but the whole point of this is so + // that it can't be changed + state->mutationsPtr = state->extra; + state->state = i; + + return i; +} +@end + +template +NSArray *RLMCollectionValueForKey(Collection& collection, NSString *key, RLMClassInfo& info) { + size_t count = collection.size(); + if (count == 0) { + return @[]; + } + + NSMutableArray *array = [NSMutableArray arrayWithCapacity:count]; + if ([key isEqualToString:@"self"]) { + RLMAccessorContext context(info); + for (size_t i = 0; i < count; ++i) { + [array addObject:collection.get(context, i) ?: NSNull.null]; + } + return array; + } + + if (collection.get_type() != realm::PropertyType::Object) { + RLMAccessorContext context(info); + for (size_t i = 0; i < count; ++i) { + [array addObject:[collection.get(context, i) valueForKey:key] ?: NSNull.null]; + } + return array; + } + + RLMObject *accessor = RLMCreateManagedAccessor(info.rlmObjectSchema.accessorClass, &info); + auto prop = info.rlmObjectSchema[key]; + + // Collection properties need to be handled specially since we need to create + // a new collection each time + if (info.rlmObjectSchema.isSwiftClass) { + if (prop.collection && prop.swiftAccessor) { + // Grab the actual class for the generic collection from an instance of it + // so that we can make instances of the collection without creating a new + // object accessor each time + Class cls = [[prop.swiftAccessor get:prop on:accessor] class]; + for (size_t i = 0; i < count; ++i) { + RLMSwiftCollectionBase *base = [[cls alloc] init]; + base._rlmCollection = [[[cls _backingCollectionType] alloc] + initWithParent:collection.get(i) property:prop parentInfo:info]; + [array addObject:base]; + } + return array; + } + } + + auto swiftAccessor = prop.swiftAccessor; + for (size_t i = 0; i < count; i++) { + accessor->_row = collection.get(i); + if (swiftAccessor) { + [swiftAccessor initialize:prop on:accessor]; + } + [array addObject:[accessor valueForKey:key] ?: NSNull.null]; + } + return array; +} + +realm::ColKey columnForProperty(NSString *propertyName, + realm::object_store::Collection const& backingCollection, + RLMClassInfo *objectInfo, + RLMPropertyType propertyType, + RLMCollectionType collectionType) { + if (backingCollection.get_type() == realm::PropertyType::Object) { + return objectInfo->tableColumn(propertyName); + } + if (![propertyName isEqualToString:@"self"]) { + NSString *collectionTypeName; + switch (collectionType) { + case RLMCollectionTypeArray: + collectionTypeName = @"Arrays"; + break; + case RLMCollectionTypeSet: + collectionTypeName = @"Sets"; + break; + case RLMCollectionTypeDictionary: + collectionTypeName = @"Dictionaries"; + break; + } + @throw RLMException(@"%@ of '%@' can only be aggregated on \"self\"", + collectionTypeName, RLMTypeToString(propertyType)); + } + return {}; +} + +template NSArray *RLMCollectionValueForKey(realm::Results&, NSString *, RLMClassInfo&); +template NSArray *RLMCollectionValueForKey(realm::List&, NSString *, RLMClassInfo&); +template NSArray *RLMCollectionValueForKey(realm::object_store::Set&, NSString *, RLMClassInfo&); + +void RLMCollectionSetValueForKey(id collection, NSString *key, id value) { + realm::TableView tv = [collection tableView]; + if (tv.size() == 0) { + return; + } + + RLMClassInfo *info = collection.objectInfo; + RLMObject *accessor = RLMCreateManagedAccessor(info->rlmObjectSchema.accessorClass, info); + for (size_t i = 0; i < tv.size(); i++) { + accessor->_row = tv[i]; + RLMInitializeSwiftAccessor(accessor, false); + [accessor setValue:value forKey:key]; + } +} + +void RLMAssignToCollection(id collection, id value) { + [(id)collection replaceAllObjectsWithObjects:value]; +} + +NSString *RLMDescriptionWithMaxDepth(NSString *name, + id collection, + NSUInteger depth) { + if (depth == 0) { + return @""; + } + + const NSUInteger maxObjects = 100; + auto str = [NSMutableString stringWithFormat:@"%@<%@> <%p> (\n", name, + [collection objectClassName] ?: RLMTypeToString([collection type]), + (void *)collection]; + size_t index = 0, skipped = 0; + for (id obj in collection) { + NSString *sub; + if ([obj respondsToSelector:@selector(descriptionWithMaxDepth:)]) { + sub = [obj descriptionWithMaxDepth:depth - 1]; + } + else { + sub = [obj description]; + } + + // Indent child objects + NSString *objDescription = [sub stringByReplacingOccurrencesOfString:@"\n" + withString:@"\n\t"]; + [str appendFormat:@"\t[%zu] %@,\n", index++, objDescription]; + if (index >= maxObjects) { + skipped = collection.count - maxObjects; + break; + } + } + + // Remove last comma and newline characters + if (collection.count > 0) { + [str deleteCharactersInRange:NSMakeRange(str.length-2, 2)]; + } + if (skipped) { + [str appendFormat:@"\n\t... %zu objects skipped.", skipped]; + } + [str appendFormat:@"\n)"]; + return str; +} + +std::vector> RLMSortDescriptorsToKeypathArray(NSArray *properties) { + std::vector> keypaths; + keypaths.reserve(properties.count); + for (RLMSortDescriptor *desc in properties) { + if ([desc.keyPath rangeOfString:@"@"].location != NSNotFound) { + @throw RLMException(@"Cannot sort on key path '%@': KVC collection operators are not supported.", desc.keyPath); + } + keypaths.push_back({desc.keyPath.UTF8String, desc.ascending}); + } + return keypaths; +} + +@implementation RLMCollectionChange { + realm::CollectionChangeSet _indices; +} + +- (instancetype)initWithChanges:(realm::CollectionChangeSet)indices { + self = [super init]; + if (self) { + _indices = std::move(indices); + } + return self; +} + +static NSArray *toArray(realm::IndexSet const& set) { + NSMutableArray *ret = [NSMutableArray new]; + for (auto index : set.as_indexes()) { + [ret addObject:@(index)]; + } + return ret; +} + +- (NSArray *)insertions { + return toArray(_indices.insertions); +} + +- (NSArray *)deletions { + return toArray(_indices.deletions); +} + +- (NSArray *)modifications { + return toArray(_indices.modifications); +} + +- (NSArray *)deletionsInSection:(NSUInteger)section { + return RLMToIndexPathArray(_indices.deletions, section); +} + +- (NSArray *)insertionsInSection:(NSUInteger)section { + return RLMToIndexPathArray(_indices.insertions, section); +} + +- (NSArray *)modificationsInSection:(NSUInteger)section { + return RLMToIndexPathArray(_indices.modifications, section); +} + +- (NSString *)description { + return [NSString stringWithFormat:@" insertions: %@, deletions: %@, modifications: %@", + (__bridge void *)self, self.insertions, self.deletions, self.modifications]; +} + +@end + +namespace { +struct CollectionCallbackWrapper { + void (^block)(id, id, NSError *); + id collection; + bool ignoreChangesInInitialNotification; + + void operator()(realm::CollectionChangeSet const& changes) { + if (ignoreChangesInInitialNotification) { + ignoreChangesInInitialNotification = false; + block(collection, nil, nil); + } + else if (changes.empty()) { + block(collection, nil, nil); + } + else if (!changes.collection_root_was_deleted || !changes.deletions.empty()) { + block(collection, [[RLMCollectionChange alloc] initWithChanges:changes], nil); + } + } +}; +} // anonymous namespace + +@interface RLMCancellationToken : RLMNotificationToken +@end + +RLM_HIDDEN +@implementation RLMCancellationToken { + __unsafe_unretained RLMRealm *_realm; + realm::NotificationToken _token; + RLMUnfairMutex _mutex; +} + +- (RLMRealm *)realm { + std::lock_guard lock(_mutex); + return _realm; +} + +- (void)suppressNextNotification { + std::lock_guard lock(_mutex); + if (_realm) { + _token.suppress_next(); + } +} + +- (bool)invalidate { + std::lock_guard lock(_mutex); + if (_realm) { + _token = {}; + _realm = nil; + return true; + } + return false; +} + +RLMNotificationToken *RLMAddNotificationBlock(id c, id block, + NSArray *keyPaths, + dispatch_queue_t queue) { + id collection = c; + RLMRealm *realm = collection.realm; + if (!realm) { + @throw RLMException(@"Change notifications are only supported on managed collections."); + } + auto token = [[RLMCancellationToken alloc] init]; + token->_realm = realm; + + RLMClassInfo *info = collection.objectInfo; + if (!queue) { + [realm verifyNotificationsAreSupported:true]; + token->_token = [collection addNotificationCallback:block keyPaths:info->keyPathArrayFromStringArray(keyPaths)]; + return token; + } + + RLMThreadSafeReference *tsr = [RLMThreadSafeReference referenceWithThreadConfined:collection]; + RLMRealmConfiguration *config = realm.configuration; + dispatch_async(queue, ^{ + std::lock_guard lock(token->_mutex); + if (!token->_realm) { + return; + } + RLMRealm *realm = token->_realm = [RLMRealm realmWithConfiguration:config queue:queue error:nil]; + id collection = [realm resolveThreadSafeReference:tsr]; + token->_token = [collection addNotificationCallback:block keyPaths:info->keyPathArrayFromStringArray(keyPaths)]; + }); + return token; +} + +realm::CollectionChangeCallback RLMWrapCollectionChangeCallback(void (^block)(id, id, NSError *), + id collection, bool skipFirst) { + return CollectionCallbackWrapper{block, collection, skipFirst}; +} +@end + +NSArray *RLMToIndexPathArray(realm::IndexSet const& set, NSUInteger section) { + NSMutableArray *ret = [NSMutableArray new]; + NSUInteger path[2] = {section, 0}; + for (auto index : set.as_indexes()) { + path[1] = index; + [ret addObject:[NSIndexPath indexPathWithIndexes:path length:2]]; + } + return ret; +} diff --git a/Pods/Realm/Realm/RLMConstants.m b/Pods/Realm/Realm/RLMConstants.m new file mode 100644 index 0000000..f7d2433 --- /dev/null +++ b/Pods/Realm/Realm/RLMConstants.m @@ -0,0 +1,32 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import + +RLMNotification const RLMRealmRefreshRequiredNotification = @"RLMRealmRefreshRequiredNotification"; +RLMNotification const RLMRealmDidChangeNotification = @"RLMRealmDidChangeNotification"; + +NSString * const RLMExceptionName = @"RLMException"; + +NSString * const RLMRealmVersionKey = @"RLMRealmVersion"; + +NSString * const RLMRealmCoreVersionKey = @"RLMRealmCoreVersion"; + +NSString * const RLMInvalidatedKey = @"invalidated"; + +NSString * const RLMBackupRealmConfigurationErrorKey = @"RLMBackupRealmConfiguration"; diff --git a/Pods/Realm/Realm/RLMCredentials.mm b/Pods/Realm/Realm/RLMCredentials.mm new file mode 100644 index 0000000..ac6d2eb --- /dev/null +++ b/Pods/Realm/Realm/RLMCredentials.mm @@ -0,0 +1,87 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMCredentials_Private.hpp" + +#import "RLMBSON_Private.hpp" +#import "RLMUtil.hpp" + +#import + +using namespace realm::app; + +@implementation RLMCredentials +- (instancetype)initWithAppCredentials:(AppCredentials&&)credentials { + if (self = [super init]) { + _appCredentials = std::move(credentials); + _provider = @(_appCredentials.provider_as_string().data()); + return self; + } + return nil; +} + ++ (instancetype)credentialsWithFacebookToken:(RLMCredentialsToken)token { + return [[self alloc] initWithAppCredentials:AppCredentials::facebook(token.UTF8String)]; +} + ++ (instancetype)credentialsWithGoogleAuthCode:(RLMCredentialsToken)token { + return [[self alloc] initWithAppCredentials:AppCredentials::google(AuthCode(token.UTF8String))]; +} + ++ (instancetype)credentialsWithGoogleIdToken:(RLMCredentialsToken)token { + return [[self alloc] initWithAppCredentials:AppCredentials::google(IdToken(token.UTF8String))]; +} + ++ (instancetype)credentialsWithAppleToken:(RLMCredentialsToken)token { + return [[self alloc] initWithAppCredentials:AppCredentials::apple(token.UTF8String)]; +} + ++ (instancetype)credentialsWithEmail:(NSString *)username + password:(NSString *)password { + return [[self alloc] initWithAppCredentials:AppCredentials::username_password(username.UTF8String, + password.UTF8String)]; +} + ++ (instancetype)credentialsWithJWT:(NSString *)token { + return [[self alloc] initWithAppCredentials:AppCredentials::custom(token.UTF8String)]; +} + ++ (instancetype)credentialsWithFunctionPayload:(NSDictionary> *)payload { + return [[self alloc] initWithAppCredentials:AppCredentials::function(static_cast(RLMConvertRLMBSONToBson(payload)))]; +} + ++ (instancetype)credentialsWithUserAPIKey:(NSString *)apiKey { + return [[self alloc] initWithAppCredentials:AppCredentials::api_key(apiKey.UTF8String)]; +} + ++ (instancetype)credentialsWithServerAPIKey:(NSString *)apiKey { + return [[self alloc] initWithAppCredentials:AppCredentials::api_key(apiKey.UTF8String)]; +} + ++ (instancetype)anonymousCredentials { + return [[self alloc] initWithAppCredentials:AppCredentials::anonymous()]; +} + +- (BOOL)isEqual:(id)object { + if (auto that = RLMDynamicCast(object)) { + return [self.provider isEqualToString:that.provider] + && self.appCredentials.serialize_as_json() == that.appCredentials.serialize_as_json(); + } + return NO; +} +@end diff --git a/Pods/Realm/Realm/RLMDecimal128.mm b/Pods/Realm/Realm/RLMDecimal128.mm new file mode 100644 index 0000000..3a70174 --- /dev/null +++ b/Pods/Realm/Realm/RLMDecimal128.mm @@ -0,0 +1,220 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMDecimal128_Private.hpp" + +#import "RLMUtil.hpp" + +#import + +// Swift's obj-c bridging does not support making an obj-c defined class conform +// to Decodable, so we need a Swift-defined subclass for that. This means that +// when Realm Swift is being used, we need to produce objects of that type rather +// than our obj-c defined type. objc_runtime_visible marks the type as being +// visible only to the obj-c runtime and not the linker, which means that it'll +// be `nil` at runtime rather than being a linker error if it's not defined, and +// valid if it happens to be defined by some other library (i.e. Realm Swift). +// +// At the point where the objects are being allocated we generally don't have +// any good way of knowing whether or not it's going to end up being used by +// Swift, so we just switch to the subclass unconditionally if the subclass +// exists. This shouldn't have any impact on obj-c code other than a small +// performance hit. +[[clang::objc_runtime_visible]] +@interface RealmSwiftDecimal128 : RLMDecimal128 +@end + +@implementation RLMDecimal128 { + realm::Decimal128 _value; +} + +- (instancetype)init { + if (self = [super init]) { + if (auto cls = [RealmSwiftDecimal128 class]; cls && cls != self.class) { + object_setClass(self, cls); + } + } + return self; +} + +- (instancetype)initWithDecimal128:(realm::Decimal128)value { + if ((self = [self init])) { + _value = value; + } + return self; +} + +- (instancetype)initWithValue:(id)value { + if ((self = [self init])) { + _value = RLMObjcToDecimal128(value); + } + return self; +} + +- (instancetype)initWithNumber:(NSNumber *)number { + if ((self = [self init])) { + _value = RLMObjcToDecimal128(number); + } + return self; +} + +- (instancetype)initWithString:(NSString *)string error:(__unused NSError **)error { + if ((self = [self init])) { + _value = realm::Decimal128(string.UTF8String); + } + return self; +} + ++ (instancetype)decimalWithNumber:(NSNumber *)number { + return [[self alloc] initWithNumber:number]; +} + ++ (instancetype)decimalWithNSDecimal:(NSDecimalNumber *)number { + return [[self alloc] initWithString:number.stringValue error:nil]; +} + +- (id)copyWithZone:(NSZone *)zone { + RLMDecimal128 *copy = [[self.class allocWithZone:zone] init]; + copy->_value = _value; + return copy; +} + +- (realm::Decimal128)decimal128Value { + return _value; +} + +- (BOOL)isEqual:(id)object { + if (auto decimal128 = RLMDynamicCast(object)) { + return _value == decimal128->_value; + } + if (auto number = RLMDynamicCast(object)) { + return _value == RLMObjcToDecimal128(number); + } + return NO; +} + +- (NSUInteger)hash { + return @(self.doubleValue).hash; +} + +- (NSString *)description { + return self.stringValue; +} + +- (NSComparisonResult)compare:(RLMDecimal128 *)other { + return static_cast(_value.compare(other->_value)); +} + +- (double)doubleValue { + return [NSDecimalNumber decimalNumberWithDecimal:self.decimalValue].doubleValue; +} + +- (NSDecimal)decimalValue { + NSDecimal ret; + [[[NSScanner alloc] initWithString:@(_value.to_string().c_str())] scanDecimal:&ret]; + return ret; +} + +- (NSString *)stringValue { + auto str = _value.to_string(); + // If there's a decimal point, trim trailing zeroes + auto decimal_pos = str.find('.'); + if (decimal_pos != std::string::npos) { + // Look specifically at the range between the decimal point and the E + // if it's present, and the rest of the string if not + std::string_view sv = str; + auto e_pos = str.find('E', decimal_pos); + if (e_pos != std::string::npos) { + sv = sv.substr(0, e_pos); + } + + // Remove everything between the character after the final non-zero + // and the end of the string (or the E) + auto final_non_zero = sv.find_last_not_of('0'); + REALM_ASSERT(final_non_zero != std::string::npos); + if (final_non_zero == decimal_pos) { + // Also drop the decimal if there's no non-zero digits after it + --final_non_zero; + } + str.erase(final_non_zero + 1, sv.size() - final_non_zero - 1); + } + return @(str.c_str()); +} + +- (BOOL)isNaN { + return _value.is_nan(); +} + +- (RLMDecimal128 *)magnitude { + auto result = realm::Decimal128(abs(self.doubleValue)); + return [[RLMDecimal128 alloc] initWithDecimal128:result]; +} + +- (void)negate { + _value = realm::Decimal128(-self.doubleValue); +} + ++ (RLMDecimal128 *)minimumDecimalNumber { + return [[RLMDecimal128 alloc] initWithDecimal128:std::numeric_limits::lowest()]; +} + ++ (RLMDecimal128 *)maximumDecimalNumber { + return [[RLMDecimal128 alloc] initWithDecimal128:std::numeric_limits::max()]; +} + +- (RLMDecimal128 *)decimalNumberByAdding:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return [[RLMDecimal128 alloc] initWithDecimal128:_value+rhs]; +} + +- (RLMDecimal128 *)decimalNumberByDividingBy:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return [[RLMDecimal128 alloc] initWithDecimal128:_value/rhs]; +} + +- (RLMDecimal128 *)decimalNumberBySubtracting:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return [[RLMDecimal128 alloc] initWithDecimal128:_value-rhs]; +} + +- (RLMDecimal128 *)decimalNumberByMultiplyingBy:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return [[RLMDecimal128 alloc] initWithDecimal128:_value*rhs]; +} + +- (BOOL)isGreaterThan:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return _value > rhs; +} + +- (BOOL)isGreaterThanOrEqualTo:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return _value >= rhs; +} + +- (BOOL)isLessThan:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return _value < rhs; +} + +- (BOOL)isLessThanOrEqualTo:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return _value <= rhs; +} + +@end diff --git a/Pods/Realm/Realm/RLMDictionary.mm b/Pods/Realm/Realm/RLMDictionary.mm new file mode 100644 index 0000000..650a011 --- /dev/null +++ b/Pods/Realm/Realm/RLMDictionary.mm @@ -0,0 +1,563 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2021 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMDictionary_Private.hpp" +#import "RLMObject_Private.h" +#import "RLMObjectSchema.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMSchema_Private.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +@interface RLMDictionary () +@end + +@implementation NSString (RLMDictionaryKey) +@end + +@implementation RLMDictionary { +@public + // Backing dictionary when this instance is unmanaged + NSMutableDictionary *_backingCollection; +} + +#pragma mark Initializers + +- (instancetype)initWithObjectClassName:(__unsafe_unretained NSString *const)objectClassName + keyType:(RLMPropertyType)keyType { + REALM_ASSERT([objectClassName length] > 0); + REALM_ASSERT(RLMValidateKeyType(keyType)); + self = [super init]; + if (self) { + _objectClassName = objectClassName; + _type = RLMPropertyTypeObject; + _keyType = keyType; + _optional = YES; + } + return self; +} + +- (instancetype)initWithObjectType:(RLMPropertyType)type optional:(BOOL)optional keyType:(RLMPropertyType)keyType { + REALM_ASSERT(RLMValidateKeyType(keyType)); + REALM_ASSERT(type != RLMPropertyTypeObject); + self = [super init]; + if (self) { + _type = type; + _keyType = keyType; + _optional = optional; + } + return self; +} + +- (void)setParent:(RLMObjectBase *)parentObject property:(RLMProperty *)property { + _parentObject = parentObject; + _key = property.name; + _isLegacyProperty = property.isLegacy; +} + +static bool RLMValidateKeyType(RLMPropertyType keyType) { + switch (keyType) { + case RLMPropertyTypeString: + return true; + default: + return false; + } +} + +id RLMDictionaryKey(__unsafe_unretained RLMDictionary *const dictionary, + __unsafe_unretained id const key) { + if (!key) { + @throw RLMException(@"Invalid nil key for dictionary expecting key of type '%@'.", + dictionary->_objectClassName ?: RLMTypeToString(dictionary.keyType)); + } + id validated = RLMValidateValue(key, dictionary.keyType, false, false, nil); + if (!validated) { + @throw RLMException(@"Invalid key '%@' of type '%@' for expected type '%@'.", + key, [key class], RLMTypeToString(dictionary.keyType)); + } + return validated; +} + +id RLMDictionaryValue(__unsafe_unretained RLMDictionary *const dictionary, + __unsafe_unretained id const value) { + if (!value) { + return value; + } + if (dictionary->_type != RLMPropertyTypeObject) { + id validated = RLMValidateValue(value, dictionary->_type, dictionary->_optional, false, nil); + if (!validated) { + @throw RLMException(@"Invalid value '%@' of type '%@' for expected type '%@%s'.", + value, [value class], RLMTypeToString(dictionary->_type), + dictionary->_optional ? "?" : ""); + } + return validated; + } + + if (auto valueObject = RLMDynamicCast(value)) { + if (!valueObject->_objectSchema) { + @throw RLMException(@"Object cannot be inserted unless the schema is initialized. " + "This can happen if you try to insert objects into a RLMDictionary / Map from a default value or from an overridden unmanaged initializer (`init()`) or if the key is uninitialized."); + } + if (![dictionary->_objectClassName isEqualToString:valueObject->_objectSchema.className]) { + @throw RLMException(@"Value of type '%@' does not match RLMDictionary value type '%@'.", + valueObject->_objectSchema.className, dictionary->_objectClassName); + } + } + else if (![value isKindOfClass:NSNull.class]) { + @throw RLMException(@"Value of type '%@' does not match RLMDictionary value type '%@'.", + [value className], dictionary->_objectClassName); + } + + return value; +} + +static void changeDictionary(__unsafe_unretained RLMDictionary *const dictionary, + dispatch_block_t f) { + if (!dictionary->_backingCollection) { + dictionary->_backingCollection = [NSMutableDictionary new]; + } + if (RLMObjectBase *parent = dictionary->_parentObject) { + [parent willChangeValueForKey:dictionary->_key]; + f(); + [parent didChangeValueForKey:dictionary->_key]; + } + else { + f(); + } +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMDictionary *, RLMDictionaryChange *, NSError *))block { + return RLMAddNotificationBlock(self, block, nil, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMDictionary *, RLMDictionaryChange *, NSError *))block + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMDictionary *, RLMDictionaryChange *, NSError *))block + keyPaths:(nullable NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, keyPaths, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMDictionary *, RLMDictionaryChange *, NSError *))block + keyPaths:(nullable NSArray *)keyPaths { + return RLMAddNotificationBlock(self, block, keyPaths, nil); +} +#pragma clang diagnostic pop + +#pragma mark - Unmanaged RLMDictionary implementation + +- (RLMRealm *)realm { + return nil; +} + +- (NSUInteger)count { + return _backingCollection.count; +} + +- (NSArray *)allKeys { + return _backingCollection.allKeys ?: @[]; +} + +- (NSArray *)allValues { + return _backingCollection.allValues ?: @[]; +} + +- (nullable id)objectForKey:(id)key { + if (!_backingCollection) { + _backingCollection = [NSMutableDictionary new]; + } + return [_backingCollection objectForKey:key]; +} + +- (nullable id)objectForKeyedSubscript:(id)key { + return [self objectForKey:key]; +} + +- (BOOL)isInvalidated { + return NO; +} + +- (void)setValue:(nullable id)value forKey:(nonnull NSString *)key { + [self setObject:value forKeyedSubscript:key]; +} + +- (void)setDictionary:(id)dictionary { + if (!dictionary || dictionary == NSNull.null) { + return [self removeAllObjects]; + } + if (![dictionary respondsToSelector:@selector(enumerateKeysAndObjectsUsingBlock:)]) { + @throw RLMException(@"Cannot set dictionary to object of class '%@'", [dictionary className]); + } + + changeDictionary(self, ^{ + [_backingCollection removeAllObjects]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *) { + [_backingCollection setObject:RLMDictionaryValue(self, value) + forKey:RLMDictionaryKey(self, key)]; + }]; + }); +} + +- (void)setObject:(id)obj forKeyedSubscript:(id)key { + if (obj) { + [self setObject:obj forKey:key]; + } + else { + [self removeObjectForKey:key]; + } +} + +- (void)setObject:(id)obj forKey:(id)key { + changeDictionary(self, ^{ + [_backingCollection setObject:RLMDictionaryValue(self, obj) + forKey:RLMDictionaryKey(self, key)]; + }); +} + +- (void)removeAllObjects { + changeDictionary(self, ^{ + [_backingCollection removeAllObjects]; + }); +} + +- (void)removeObjectsForKeys:(NSArray *)keyArray { + changeDictionary(self, ^{ + [_backingCollection removeObjectsForKeys:keyArray]; + }); +} + +- (void)removeObjectForKey:(id)key { + changeDictionary(self, ^{ + [_backingCollection removeObjectForKey:key]; + }); +} + +- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block { + [_backingCollection enumerateKeysAndObjectsUsingBlock:block]; +} + +- (nullable id)valueForKey:(nonnull NSString *)key { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @NO; // Unmanaged dictionaries are never invalidated + } + if (!_backingCollection) { + _backingCollection = [NSMutableDictionary new]; + } + return [_backingCollection valueForKey:key]; +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath characterAtIndex:0] != '@') { + return _backingCollection ? [_backingCollection valueForKeyPath:keyPath] : [super valueForKeyPath:keyPath]; + } + if (!_backingCollection) { + _backingCollection = [NSMutableDictionary new]; + } + NSUInteger dot = [keyPath rangeOfString:@"."].location; + if (dot == NSNotFound) { + return [_backingCollection valueForKeyPath:keyPath]; + } + + NSString *op = [keyPath substringToIndex:dot]; + NSString *key = [keyPath substringFromIndex:dot + 1]; + return [self aggregateProperty:key operation:op method:nil]; +} + +- (void)addEntriesFromDictionary:(id)otherDictionary { + if (!otherDictionary) { + return; + } + if (![otherDictionary respondsToSelector:@selector(enumerateKeysAndObjectsUsingBlock:)]) { + @throw RLMException(@"Cannot add entries from object of class '%@'", [otherDictionary className]); + } + + changeDictionary(self, ^{ + [otherDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *) { + _backingCollection[RLMDictionaryKey(self, key)] = RLMDictionaryValue(self, value); + }]; + }); +} + +- (NSUInteger)countByEnumeratingWithState:(nonnull NSFastEnumerationState *)state + objects:(__unsafe_unretained id _Nullable * _Nonnull)buffer + count:(NSUInteger)len { + return RLMUnmanagedFastEnumerate(_backingCollection.allKeys, state); +} + +#pragma mark - Aggregate operations + +- (RLMPropertyType)typeForProperty:(NSString *)propertyName { + if ([propertyName isEqualToString:@"self"]) { + return _type; + } + + RLMObjectSchema *objectSchema; + if (_backingCollection.count) { + objectSchema = [_backingCollection.allValues[0] objectSchema]; + } + else { + objectSchema = [RLMSchema.partialPrivateSharedSchema schemaForClassName:_objectClassName]; + } + + return RLMValidatedProperty(objectSchema, propertyName).type; +} + +- (id)aggregateProperty:(NSString *)key operation:(NSString *)op method:(SEL)sel { + // Although delegating to valueForKeyPath: here would allow to support + // nested key paths as well, limiting functionality gives consistency + // between unmanaged and managed arrays. + if ([key rangeOfString:@"."].location != NSNotFound) { + @throw RLMException(@"Nested key paths are not supported yet for KVC collection operators."); + } + + if ([op isEqualToString:@"@distinctUnionOfObjects"]) { + @throw RLMException(@"this class does not implement the distinctUnionOfObjects"); + } + + bool allowDate = false; + bool sum = false; + if ([op isEqualToString:@"@min"] || [op isEqualToString:@"@max"]) { + allowDate = true; + } + else if ([op isEqualToString:@"@sum"]) { + sum = true; + } + else if (![op isEqualToString:@"@avg"]) { + // Just delegate to NSDictionary for all other operators + return [_backingCollection valueForKeyPath:[op stringByAppendingPathExtension:key]]; + } + + RLMPropertyType type = [self typeForProperty:key]; + if (!canAggregate(type, allowDate)) { + NSString *method = sel ? NSStringFromSelector(sel) : op; + if (_type == RLMPropertyTypeObject) { + @throw RLMException(@"%@: is not supported for %@ property '%@.%@'", + method, RLMTypeToString(type), _objectClassName, key); + } + else { + @throw RLMException(@"%@ is not supported for %@%s dictionary", + method, RLMTypeToString(_type), _optional ? "?" : ""); + } + } + + NSArray *values = [key isEqualToString:@"self"] ? _backingCollection.allValues : [_backingCollection.allValues valueForKey:key]; + + if (_optional) { + // Filter out NSNull values to match our behavior on managed arrays + NSIndexSet *nonnull = [values indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger, BOOL *) { + return obj != NSNull.null; + }]; + if (nonnull.count < values.count) { + values = [values objectsAtIndexes:nonnull]; + } + } + id result = [values valueForKeyPath:[op stringByAppendingString:@".self"]]; + return sum && !result ? @0 : result; +} + +- (id)minOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@min" method:_cmd]; +} + +- (id)maxOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@max" method:_cmd]; +} + +- (id)sumOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@sum" method:_cmd]; +} + +- (id)averageOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@avg" method:_cmd]; +} + +- (nonnull RLMResults *)objectsWhere:(nonnull NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsWhere:predicateFormat args:args]; + va_end(args); + return results; +} + +- (nonnull RLMResults *)objectsWhere:(nonnull NSString *)predicateFormat args:(va_list)args { + return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (BOOL)isEqual:(id)object { + if (auto dictionary = RLMDynamicCast(object)) { + return !dictionary.realm + && ((_backingCollection.count == 0 && dictionary->_backingCollection.count == 0) + || [_backingCollection isEqual:dictionary->_backingCollection]); + } + return NO; +} + +- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options context:(void *)context { + RLMDictionaryValidateObservationKey(keyPath, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +#pragma mark - Key Path Strings + +- (NSString *)propertyKey { + return _key; +} + +#pragma mark - Methods unsupported on unmanaged RLMDictionary instances + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" + +- (nonnull RLMResults *)objectsWithPredicate:(nonnull NSPredicate *)predicate { + @throw RLMException(@"This method may only be called on RLMDictionary instances retrieved from an RLMRealm"); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(nonnull NSArray *)properties { + @throw RLMException(@"This method may only be called on RLMDictionary instances retrieved from an RLMRealm"); +} + +- (RLMResults *)sortedResultsUsingKeyPath:(nonnull NSString *)keyPath ascending:(BOOL)ascending { + @throw RLMException(@"This method may only be called on RLMDictionary instances retrieved from an RLMRealm"); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + @throw RLMException(@"This method may only be called on RLMDictionary instances retrieved from an RLMRealm"); +} + +- (instancetype)freeze { + @throw RLMException(@"This method may only be called on RLMDictionary instances retrieved from an RLMRealm"); +} + +- (instancetype)thaw { + @throw RLMException(@"This method may only be called on RLMDictionary instances retrieved from an RLMRealm"); +} + +- (NSUInteger)indexOfObject:(id)value { + @throw RLMException(@"This method is not available on RLMDictionary."); +} + +- (id)objectAtIndex:(NSUInteger)index { + @throw RLMException(@"This method is not available on RLMDictionary."); +} + +- (nullable NSArray *)objectsAtIndexes:(nonnull NSIndexSet *)indexes { + @throw RLMException(@"This method is not available on RLMDictionary."); +} + +- (RLMSectionedResults *)sectionedResultsSortedUsingKeyPath:(NSString *)keyPath + ascending:(BOOL)ascending + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + @throw RLMException(@"This method is not available on RLMDictionary."); +} + +- (RLMSectionedResults *)sectionedResultsUsingSortDescriptors:(NSArray *)sortDescriptors + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + @throw RLMException(@"This method is not available on RLMDictionary."); +} + +#pragma clang diagnostic pop // unused parameter warning + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMDictionary`"); +} + +- (id)objectiveCMetadata { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMDictionary`"); +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(id)metadata + realm:(RLMRealm *)realm { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMDictionary`"); +} + +#pragma mark - Superclass Overrides + +- (NSString *)description { + return [self descriptionWithMaxDepth:RLMDescriptionMaxDepth]; +} + +- (NSString *)descriptionWithMaxDepth:(NSUInteger)depth { + return RLMDictionaryDescriptionWithMaxDepth(@"RLMDictionary", self, depth); +} + +NSString *RLMDictionaryDescriptionWithMaxDepth(NSString *name, + RLMDictionary *dictionary, + NSUInteger depth) { + if (depth == 0) { + return @""; + } + + const NSUInteger maxObjects = 100; + auto str = [NSMutableString stringWithFormat:@"%@<%@, %@> <%p> (\n", name, + RLMTypeToString([dictionary keyType]), + [dictionary objectClassName] ?: RLMTypeToString([dictionary type]), + (void *)dictionary]; + size_t index = 0, skipped = 0; + for (id key in dictionary) { + id value = dictionary[key]; + NSString *keyDesc; + if ([key respondsToSelector:@selector(descriptionWithMaxDepth:)]) { + keyDesc = [key descriptionWithMaxDepth:depth - 1]; + } + else { + keyDesc = [key description]; + } + NSString *valDesc; + if ([value respondsToSelector:@selector(descriptionWithMaxDepth:)]) { + valDesc = [value descriptionWithMaxDepth:depth - 1]; + } + else { + valDesc = [value description]; + } + + // Indent child objects + NSString *sub = [NSString stringWithFormat:@"[%@]: %@", keyDesc, valDesc]; + NSString *objDescription = [sub stringByReplacingOccurrencesOfString:@"\n" + withString:@"\n\t"]; + [str appendFormat:@"%@,\n", objDescription]; + if (index >= maxObjects) { + skipped = dictionary.count - maxObjects; + break; + } + } + + // Remove last comma and newline characters + if (dictionary.count > 0) { + [str deleteCharactersInRange:NSMakeRange(str.length-2, 2)]; + } + if (skipped) { + [str appendFormat:@"\n\t... %zu objects skipped.", skipped]; + } + [str appendFormat:@"\n)"]; + return str; +} + +@end diff --git a/Pods/Realm/Realm/RLMEmailPasswordAuth.mm b/Pods/Realm/Realm/RLMEmailPasswordAuth.mm new file mode 100644 index 0000000..890fb20 --- /dev/null +++ b/Pods/Realm/Realm/RLMEmailPasswordAuth.mm @@ -0,0 +1,78 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMEmailPasswordAuth.h" + +#import "RLMApp_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMProviderClient_Private.hpp" + +#import + +@implementation RLMEmailPasswordAuth + +- (realm::app::App::UsernamePasswordProviderClient)client { + return self.app._realmApp->provider_client(); +} + +- (void)registerUserWithEmail:(NSString *)email + password:(NSString *)password + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.register_email(email.UTF8String, password.UTF8String, RLMWrapCompletion(completion)); +} + +- (void)confirmUser:(NSString *)token + tokenId:(NSString *)tokenId + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.confirm_user(token.UTF8String, tokenId.UTF8String, RLMWrapCompletion(completion)); +} + +- (void)retryCustomConfirmation:(NSString *)email + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.retry_custom_confirmation(email.UTF8String, RLMWrapCompletion(completion)); +} + +- (void)resendConfirmationEmail:(NSString *)email + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.resend_confirmation_email(email.UTF8String, RLMWrapCompletion(completion)); +} + +- (void)sendResetPasswordEmail:(NSString *)email + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.send_reset_password_email(email.UTF8String, RLMWrapCompletion(completion)); +} + +- (void)resetPasswordTo:(NSString *)password + token:(NSString *)token + tokenId:(NSString *)tokenId + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.reset_password(password.UTF8String, token.UTF8String, tokenId.UTF8String, + RLMWrapCompletion(completion)); +} + +- (void)callResetPasswordFunction:(NSString *)email + password:(NSString *)password + args:(NSArray> *)args + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.call_reset_password_function(email.UTF8String, + password.UTF8String, + static_cast(RLMConvertRLMBSONToBson(args)), + RLMWrapCompletion(completion)); +} + +@end diff --git a/Pods/Realm/Realm/RLMEmbeddedObject.mm b/Pods/Realm/Realm/RLMEmbeddedObject.mm new file mode 100644 index 0000000..fb216e5 --- /dev/null +++ b/Pods/Realm/Realm/RLMEmbeddedObject.mm @@ -0,0 +1,123 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMEmbeddedObject.h" + +#import "RLMObject_Private.hpp" +#import "RLMSchema_Private.h" + +@implementation RLMEmbeddedObject +// synthesized in RLMObjectBase but redeclared here for documentation purposes +@dynamic invalidated, realm, objectSchema; + +#pragma mark - Designated Initializers + +- (instancetype)init { + return [super init]; +} + +#pragma mark - Convenience Initializers + +- (instancetype)initWithValue:(id)value { + if (!(self = [self init])) { + return nil; + } + RLMInitializeWithValue(self, value, RLMSchema.partialPrivateSharedSchema); + return self; +} + +#pragma mark - Subscripting + +- (id)objectForKeyedSubscript:(NSString *)key { + return RLMObjectBaseObjectForKeyedSubscript(self, key); +} + +- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key { + RLMObjectBaseSetObjectForKeyedSubscript(self, key, obj); +} + +#pragma mark - Other Instance Methods + +- (BOOL)isEqualToObject:(RLMObjectBase *)object { + return [object isKindOfClass:RLMObjectBase.class] && RLMObjectBaseAreEqual(self, object); +} + +- (instancetype)freeze { + return RLMObjectFreeze(self); +} + +- (instancetype)thaw { + return RLMObjectThaw(self); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block { + return RLMObjectAddNotificationBlock(self, block, nil, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block queue:(dispatch_queue_t)queue { + return RLMObjectAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block keyPaths:(NSArray *)keyPaths { + return RLMObjectAddNotificationBlock(self, block, keyPaths, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMObjectAddNotificationBlock(self, block, keyPaths, queue); +} + ++ (NSString *)className { + return [super className]; +} + +#pragma mark - Default values for schema definition + ++ (NSString *)primaryKey { + return nil; +} + ++ (NSArray *)indexedProperties { + return @[]; +} + ++ (NSDictionary *)linkingObjectsProperties { + return @{}; +} + ++ (NSDictionary *)defaultPropertyValues { + return nil; +} + ++ (NSArray *)ignoredProperties { + return nil; +} + ++ (NSArray *)requiredProperties { + return @[]; +} + ++ (bool)_realmIgnoreClass { + return false; +} + ++ (bool)isEmbedded { + return true; +} +@end diff --git a/Pods/Realm/Realm/RLMError.mm b/Pods/Realm/Realm/RLMError.mm new file mode 100644 index 0000000..652129f --- /dev/null +++ b/Pods/Realm/Realm/RLMError.mm @@ -0,0 +1,288 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMError_Private.hpp" + +#import "RLMUtil.hpp" +#import "RLMSyncSession_Private.hpp" + +#import +#import +#import + +NSString *const RLMErrorDomain = @"io.realm"; +NSString *const RLMUnknownSystemErrorDomain = @"io.realm.unknown"; +NSString *const RLMSyncErrorDomain = @"io.realm.sync"; +NSString *const RLMSyncAuthErrorDomain = @"io.realm.sync.auth"; +NSString *const RLMAppErrorDomain = @"io.realm.app"; + +NSString *const kRLMSyncPathOfRealmBackupCopyKey = @"recovered_realm_location_path"; +NSString *const kRLMSyncErrorActionTokenKey = @"error_action_token"; +NSString *const RLMErrorCodeKey = @"Error Code"; +NSString *const RLMErrorCodeNameKey = @"Error Name"; +NSString *const RLMServerLogURLKey = @"Server Log URL"; +NSString *const RLMCompensatingWriteInfoKey = @"Compensating Write Info"; +NSString *const RLMHTTPStatusCodeKey = @"HTTP Status Code"; +static NSString *const RLMDeprecatedErrorCodeKey = @"Error Code"; + +namespace { +NSInteger translateFileError(realm::ErrorCodes::Error code) { + using ec = realm::ErrorCodes::Error; + switch (code) { + case ec::AddressSpaceExhausted: return RLMErrorAddressSpaceExhausted; + case ec::DeleteOnOpenRealm: return RLMErrorAlreadyOpen; + case ec::FileAlreadyExists: return RLMErrorFileExists; + case ec::FileFormatUpgradeRequired: return RLMErrorFileFormatUpgradeRequired; + case ec::FileNotFound: return RLMErrorFileNotFound; + case ec::FileOperationFailed: return RLMErrorFileOperationFailed; + case ec::IncompatibleHistories: return RLMErrorIncompatibleHistories; + case ec::IncompatibleLockFile: return RLMErrorIncompatibleLockFile; + case ec::IncompatibleSession: return RLMErrorIncompatibleSession; + case ec::InvalidDatabase: return RLMErrorInvalidDatabase; + case ec::MultipleSyncAgents: return RLMErrorMultipleSyncAgents; + case ec::NoSubscriptionForWrite: return RLMErrorNoSubscriptionForWrite; + case ec::OutOfDiskSpace: return RLMErrorOutOfDiskSpace; + case ec::PermissionDenied: return RLMErrorFilePermissionDenied; + case ec::SchemaMismatch: return RLMErrorSchemaMismatch; + case ec::SubscriptionFailed: return RLMErrorSubscriptionFailed; + case ec::UnsupportedFileFormatVersion: return RLMErrorUnsupportedFileFormatVersion; + + case ec::APIKeyAlreadyExists: return RLMAppErrorAPIKeyAlreadyExists; + case ec::AccountNameInUse: return RLMAppErrorAccountNameInUse; + case ec::AppUnknownError: return RLMAppErrorUnknown; + case ec::AuthError: return RLMAppErrorAuthError; + case ec::AuthProviderNotFound: return RLMAppErrorAuthProviderNotFound; + case ec::DomainNotAllowed: return RLMAppErrorDomainNotAllowed; + case ec::ExecutionTimeLimitExceeded: return RLMAppErrorExecutionTimeLimitExceeded; + case ec::FunctionExecutionError: return RLMAppErrorFunctionExecutionError; + case ec::FunctionInvalid: return RLMAppErrorFunctionInvalid; + case ec::FunctionNotFound: return RLMAppErrorFunctionNotFound; + case ec::FunctionSyntaxError: return RLMAppErrorFunctionSyntaxError; + case ec::InvalidPassword: return RLMAppErrorInvalidPassword; + case ec::InvalidSession: return RLMAppErrorInvalidSession; + case ec::MaintenanceInProgress: return RLMAppErrorMaintenanceInProgress; + case ec::MissingParameter: return RLMAppErrorMissingParameter; + case ec::MongoDBError: return RLMAppErrorMongoDBError; + case ec::NotCallable: return RLMAppErrorNotCallable; + case ec::ReadSizeLimitExceeded: return RLMAppErrorReadSizeLimitExceeded; + case ec::UserAlreadyConfirmed: return RLMAppErrorUserAlreadyConfirmed; + case ec::UserAppDomainMismatch: return RLMAppErrorUserAppDomainMismatch; + case ec::UserDisabled: return RLMAppErrorUserDisabled; + case ec::UserNotFound: return RLMAppErrorUserNotFound; + case ec::ValueAlreadyExists: return RLMAppErrorValueAlreadyExists; + case ec::ValueDuplicateName: return RLMAppErrorValueDuplicateName; + case ec::ValueNotFound: return RLMAppErrorValueNotFound; + + case ec::AWSError: + case ec::GCMError: + case ec::HTTPError: + case ec::InternalServerError: + case ec::TwilioError: + return RLMAppErrorInternalServerError; + + case ec::ArgumentsNotAllowed: + case ec::BadRequest: + case ec::InvalidParameter: + return RLMAppErrorBadRequest; + + default: { + auto category = realm::ErrorCodes::error_categories(code); + if (category.test(realm::ErrorCategory::file_access)) { + return RLMErrorFileAccess; + } + if (category.test(realm::ErrorCategory::app_error)) { + return RLMAppErrorUnknown; + } + return RLMErrorFail; + } + } +} + +NSString *errorDomain(realm::ErrorCodes::Error error) { + auto category = realm::ErrorCodes::error_categories(error); + if (category.test(realm::ErrorCategory::app_error)) { + return RLMAppErrorDomain; + } + return RLMErrorDomain; +} + +NSString *errorString(realm::ErrorCodes::Error error) { + return RLMStringViewToNSString(realm::ErrorCodes::error_string(error)); +} + +NSError *translateSystemError(std::error_code ec, const char *msg) { + int code = ec.value(); + BOOL isGenericCategoryError = ec.category() == std::generic_category() + || ec.category() == realm::util::error::basic_system_error_category(); + NSString *errorDomain = isGenericCategoryError ? NSPOSIXErrorDomain : RLMUnknownSystemErrorDomain; + + NSMutableDictionary *userInfo = [NSMutableDictionary new]; + userInfo[NSLocalizedDescriptionKey] = @(msg); + // FIXME: remove these in v11 + userInfo[@"Error Code"] = @(code); + userInfo[@"Category"] = @(ec.category().name()); + +#if REALM_ENABLE_SYNC + if (ec.category() == realm::sync::client_error_category()) { + if (code == static_cast(realm::sync::Client::Error::connect_timeout)) { + errorDomain = NSPOSIXErrorDomain; + code = ETIMEDOUT; + } + else { + errorDomain = RLMSyncErrorDomain; + } + } +#endif + + return [NSError errorWithDomain:errorDomain code:code userInfo:userInfo.copy]; +} +} // anonymous namespace + +NSError *makeError(realm::Status const& status) { + if (status.is_ok()) { + return nil; + } + auto code = translateFileError(status.code()); + return [NSError errorWithDomain:errorDomain(status.code()) + code:code + userInfo:@{NSLocalizedDescriptionKey: @(status.reason().c_str()), + RLMDeprecatedErrorCodeKey: @(code), + RLMErrorCodeNameKey: errorString(status.code())}]; +} + +NSError *makeError(realm::Exception const& exception) { + auto status = exception.to_status(); + if (status.code() == realm::ErrorCodes::SystemError && status.get_std_error_code() != std::error_code{}) { + return translateSystemError(status.get_std_error_code(), exception.what()); + } + + NSInteger code = translateFileError(exception.code()); + return [NSError errorWithDomain:errorDomain(status.code()) + code:code + userInfo:@{NSLocalizedDescriptionKey: @(exception.what()), + RLMDeprecatedErrorCodeKey: @(code), + RLMErrorCodeNameKey: errorString(exception.code())}]; + +} + +NSError *makeError(realm::FileAccessError const& exception) { + NSInteger code = translateFileError(exception.code()); + return [NSError errorWithDomain:errorDomain(exception.code()) + code:code + userInfo:@{NSLocalizedDescriptionKey: @(exception.what()), + NSFilePathErrorKey: @(exception.get_path().data()), + RLMDeprecatedErrorCodeKey: @(code), + RLMErrorCodeNameKey: errorString(exception.code())}]; +} + +NSError *makeError(std::exception const& exception) { + return [NSError errorWithDomain:RLMErrorDomain + code:RLMErrorFail + userInfo:@{NSLocalizedDescriptionKey: @(exception.what())}]; +} + +NSError *makeError(std::system_error const& exception) { + return translateSystemError(exception.code(), exception.what()); +} + +__attribute__((objc_direct_members)) +@implementation RLMCompensatingWriteInfo { + realm::sync::CompensatingWriteErrorInfo _info; +} + +- (instancetype)initWithInfo:(realm::sync::CompensatingWriteErrorInfo&&)info { + if ((self = [super init])) { + _info = std::move(info); + } + return self; +} + +- (NSString *)objectType { + return @(_info.object_name.c_str()); +} + +- (NSString *)reason { + return @(_info.reason.c_str()); +} + +- (id)primaryKey { + return RLMMixedToObjc(_info.primary_key); +} +@end + +NSError *makeError(realm::SyncError&& error) { + auto& status = error.to_status(); + if (status.is_ok()) { + return nil; + } + + NSMutableDictionary *userInfo = [NSMutableDictionary new]; + userInfo[NSLocalizedDescriptionKey] = RLMStringViewToNSString(error.simple_message); + if (!error.logURL.empty()) { + userInfo[RLMServerLogURLKey] = RLMStringViewToNSString(error.logURL); + } + if (!error.compensating_writes_info.empty()) { + NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:error.compensating_writes_info.size()]; + for (auto& info : error.compensating_writes_info) { + [array addObject:[[RLMCompensatingWriteInfo alloc] initWithInfo:std::move(info)]]; + } + userInfo[RLMCompensatingWriteInfoKey] = [array copy]; + } + for (auto& pair : error.user_info) { + if (pair.first == realm::SyncError::c_original_file_path_key) { + userInfo[kRLMSyncErrorActionTokenKey] = + [[RLMSyncErrorActionToken alloc] initWithOriginalPath:pair.second]; + } + else if (pair.first == realm::SyncError::c_recovery_file_path_key) { + userInfo[kRLMSyncPathOfRealmBackupCopyKey] = @(pair.second.c_str()); + } + } + + RLMSyncError errorCode = RLMSyncErrorClientInternalError; + if (error.is_client_reset_requested()) + errorCode = RLMSyncErrorClientResetError; + else if (error.is_session_level_protocol_error()) { + using enum realm::sync::ProtocolError; + switch (static_cast(error.to_status().get_std_error_code().value())) { + case permission_denied: errorCode = RLMSyncErrorPermissionDeniedError; break; + case bad_authentication: errorCode = RLMSyncErrorClientUserError; break; + case compensating_write: errorCode = RLMSyncErrorWriteRejected; break; + default: errorCode = RLMSyncErrorClientSessionError; + } + } + else if (!error.is_fatal) { + return nil; + } + + return [NSError errorWithDomain:RLMSyncErrorDomain code:errorCode userInfo:userInfo.copy]; +} + +NSError *makeError(realm::app::AppError const& appError) { + auto& status = appError.to_status(); + if (status.is_ok()) { + return nil; + } + + auto code = translateFileError(status.code()); + return [NSError errorWithDomain:errorDomain(status.code()) + code:code + userInfo:@{NSLocalizedDescriptionKey: @(status.reason().c_str()), + RLMDeprecatedErrorCodeKey: @(code), + RLMErrorCodeNameKey: errorString(status.code()), + RLMServerLogURLKey: @(appError.link_to_server_logs.c_str())}]; +} diff --git a/Pods/Realm/Realm/RLMEvent.mm b/Pods/Realm/Realm/RLMEvent.mm new file mode 100644 index 0000000..33da3f1 --- /dev/null +++ b/Pods/Realm/Realm/RLMEvent.mm @@ -0,0 +1,226 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import + +#import "RLMError_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMRealmUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +using namespace realm; + +@interface RLMObjectBase () +- (NSString *)customEventRepresentation; +@end + +namespace { +util::UniqueFunction wrapCompletion(void (^completion)(NSError *)) { + if (!completion) { + return nullptr; + } + return [=](std::exception_ptr err) { + @autoreleasepool { + if (!err) { + return completion(nil); + } + try { + std::rethrow_exception(err); + } + catch (NSException *e) { + auto info = @{@"ExceptionName": e.name ?: NSNull.null, + @"ExceptionReason": e.reason ?: NSNull.null, + @"ExceptionCallStackReturnAddresses": e.callStackReturnAddresses, + @"ExceptionCallStackSymbols": e.callStackSymbols, + @"ExceptionUserInfo": e.userInfo ?: NSNull.null}; + completion([NSError errorWithDomain:RLMErrorDomain code:RLMErrorFail userInfo:info]); + } + catch (...) { + NSError *error; + RLMRealmTranslateException(&error); + completion(error); + } + } + }; +} + +realm::AuditInterface *auditContext(RLMEventContext *context) { + return reinterpret_cast(context); +} + +std::vector> convertMetadata(NSDictionary *metadata) { + std::vector> ret; + ret.reserve(metadata.count); + [metadata enumerateKeysAndObjectsUsingBlock:[&](NSString *key, NSString *value, BOOL *) { + ret.emplace_back(key.UTF8String, value.UTF8String); + }]; + return ret; +} + +std::optional nsStringToOptionalString(NSString *str) { + if (!str) { + return util::none; + } + + std::string ret; + RLMNSStringToStdString(ret, str); + return ret; +} +} // anonymous namespace + +uint64_t RLMEventBeginScope(RLMEventContext *context, NSString *activity) { + return auditContext(context)->begin_scope(activity.UTF8String); +} + +void RLMEventCommitScope(RLMEventContext *context, uint64_t scope_id, RLMEventCompletion completion) { + auditContext(context)->end_scope(scope_id, wrapCompletion(completion)); +} + +void RLMEventCancelScope(RLMEventContext *context, uint64_t scope_id) { + auditContext(context)->cancel_scope(scope_id); +} + +bool RLMEventIsActive(RLMEventContext *context, uint64_t scope_id) { + return auditContext(context)->is_scope_valid(scope_id); +} + +void RLMEventRecordEvent(RLMEventContext *context, NSString *activity, NSString *event, + NSString *data, RLMEventCompletion completion) { + auditContext(context)->record_event(activity.UTF8String, nsStringToOptionalString(event), + nsStringToOptionalString(data), wrapCompletion(completion)); +} + +void RLMEventUpdateMetadata(RLMEventContext *context, NSDictionary *newMetadata) { + auditContext(context)->update_metadata(convertMetadata(newMetadata)); +} + +RLMEventContext *RLMEventGetContext(RLMRealm *realm) { + return reinterpret_cast(realm->_realm->audit_context()); +} + +class RLMEventSerializer : public realm::AuditObjectSerializer { +public: + RLMEventSerializer(RLMRealmConfiguration *c) : _config(c.copy) { + auto& config = _config.configRef; + config.cache = false; + config.audit_config = nullptr; + config.automatic_change_notifications = false; + } + + ~RLMEventSerializer() { + scope_complete(); + } + + void scope_complete() final { + for (auto& [_, acc] : _accessorMap) { + if (acc) { + acc->_realm = nil; + acc->_objectSchema = nil; + } + } + if (_realm) { + _realm->_realm->close(); + _realm = nil; + } + } + + void to_json(nlohmann::json& out, const Obj& obj) final { + @autoreleasepool { + auto tableKey = obj.get_table()->get_key(); + RLMObjectBase *acc = getAccessor(tableKey); + if (!acc) { + return AuditObjectSerializer::to_json(out, obj); + } + + if (!acc->_realm) { + acc->_realm = realm(); + acc->_info = acc->_realm->_info[tableKey]; + acc->_objectSchema = acc->_info->rlmObjectSchema; + } + + acc->_row = obj; + RLMInitializeSwiftAccessor(acc, false); + NSString *customRepresentation = [acc customEventRepresentation]; + out = nlohmann::json::parse(customRepresentation.UTF8String); + } + } + +private: + RLMRealmConfiguration *_config; + RLMRealm *_realm; + std::unordered_map _accessorMap; + + RLMRealm *realm() { + if (!_realm) { + _realm = [RLMRealm realmWithConfiguration:_config error:nil]; + } + return _realm; + } + + RLMObjectBase *getAccessor(TableKey tableKey) { + auto it = _accessorMap.find(tableKey.value); + if (it != _accessorMap.end()) { + return it->second; + } + + RLMClassInfo *info = realm()->_info[tableKey]; + if (!info || !info->rlmObjectSchema.hasCustomEventSerialization) { + _accessorMap.insert({tableKey.value, nil}); + return nil; + } + + RLMObjectBase *acc = [[info->rlmObjectSchema.accessorClass alloc] init]; + acc->_realm = realm(); + acc->_objectSchema = info->rlmObjectSchema; + acc->_info = info; + _accessorMap.insert({tableKey.value, acc}); + return acc; + } +}; + +@implementation RLMEventConfiguration +- (std::shared_ptr)auditConfigWithRealmConfiguration:(RLMRealmConfiguration *)realmConfig { + auto config = std::make_shared(); + config->audit_user = self.syncUser._syncUser; + config->partition_value_prefix = self.partitionPrefix.UTF8String; + config->metadata = convertMetadata(self.metadata); + config->serializer = std::make_shared(realmConfig); + if (_logger) { + config->logger = RLMWrapLogFunction(_logger); + } + if (_errorHandler) { + config->sync_error_handler = [eh = _errorHandler](realm::SyncError e) { + if (auto error = makeError(std::move(e))) { + eh(error); + } + }; + } + return config; +} +@end diff --git a/Pods/Realm/Realm/RLMFindOneAndModifyOptions.mm b/Pods/Realm/Realm/RLMFindOneAndModifyOptions.mm new file mode 100644 index 0000000..d21ba10 --- /dev/null +++ b/Pods/Realm/Realm/RLMFindOneAndModifyOptions.mm @@ -0,0 +1,110 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMFindOneAndModifyOptions_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMCollection.h" + +@interface RLMFindOneAndModifyOptions() { + realm::app::MongoCollection::FindOneAndModifyOptions _options; +}; +@end + +@implementation RLMFindOneAndModifyOptions + +- (instancetype)initWithProjection:(id _Nullable)projection + sort:(id _Nullable)sort + upsert:(BOOL)upsert + shouldReturnNewDocument:(BOOL)shouldReturnNewDocument { + if (self = [super init]) { + self.upsert = upsert; + self.shouldReturnNewDocument = shouldReturnNewDocument; + self.projection = projection; + self.sort = sort; + } + return self; +} + +- (instancetype)initWithProjection:(id _Nullable)projection + sorting:(NSArray> *)sorting + upsert:(BOOL)upsert + shouldReturnNewDocument:(BOOL)shouldReturnNewDocument { + if (self = [super init]) { + self.upsert = upsert; + self.shouldReturnNewDocument = shouldReturnNewDocument; + self.projection = projection; + self.sorting = sorting; + } + return self; +} + +- (realm::app::MongoCollection::FindOneAndModifyOptions)_findOneAndModifyOptions { + return _options; +} + +- (id)projection { + return RLMConvertBsonDocumentToRLMBSON(_options.projection_bson); +} + +- (id)sort { + return RLMConvertBsonDocumentToRLMBSON(_options.sort_bson); +} + +- (NSArray> *)sorting { + return RLMConvertBsonDocumentToRLMBSONArray(_options.sort_bson); +} + +- (BOOL)upsert { + return _options.upsert; +} + +- (BOOL)shouldReturnNewDocument { + return _options.return_new_document; +} + +- (void)setProjection:(id)projection { + if (projection) { + auto bson = realm::bson::BsonDocument(RLMConvertRLMBSONToBson(projection)); + _options.projection_bson = std::optional(bson); + } else { + _options.projection_bson = realm::util::none; + } +} + +- (void)setSort:(id)sort { + if (sort) { + auto bson = realm::bson::BsonDocument(RLMConvertRLMBSONToBson(sort)); + _options.sort_bson = std::optional(bson); + } else { + _options.sort_bson = realm::util::none; + } +} + +- (void)setSorting:(NSArray> *)sorting { + _options.sort_bson = RLMConvertRLMBSONArrayToBsonDocument(sorting); +} + +- (void)setUpsert:(BOOL)upsert { + _options.upsert = upsert; +} + +- (void)setShouldReturnNewDocument:(BOOL)returnNewDocument { + _options.return_new_document = returnNewDocument; +} + +@end diff --git a/Pods/Realm/Realm/RLMFindOptions.mm b/Pods/Realm/Realm/RLMFindOptions.mm new file mode 100644 index 0000000..37a2bc4 --- /dev/null +++ b/Pods/Realm/Realm/RLMFindOptions.mm @@ -0,0 +1,116 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMFindOptions_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMCollection.h" + +@interface RLMFindOptions() { + realm::app::MongoCollection::FindOptions _options; +}; +@end + +@implementation RLMFindOptions + +- (instancetype)initWithLimit:(NSInteger)limit + projection:(id _Nullable)projection + sort:(id _Nullable)sort { + if (self = [super init]) { + self.projection = projection; + self.sort = sort; + self.limit = limit; + } + return self; +} + +- (instancetype)initWithProjection:(id _Nullable)projection + sort:(id _Nullable)sort { + if (self = [super init]) { + self.projection = projection; + self.sort = sort; + } + return self; +} + +- (instancetype)initWithLimit:(NSInteger)limit + projection:(id _Nullable)projection + sorting:(NSArray> *)sorting { + if (self = [super init]) { + self.projection = projection; + self.sorting = sorting; + self.limit = limit; + } + return self; +} + +- (instancetype)initWithProjection:(id _Nullable)projection + sorting:(NSArray> *)sorting { + if (self = [super init]) { + self.projection = projection; + self.sorting = sorting; + } + return self; +} + +- (realm::app::MongoCollection::FindOptions)_findOptions { + return _options; +} + +- (id)projection { + return RLMConvertBsonDocumentToRLMBSON(_options.projection_bson); +} + +- (id)sort { + return RLMConvertBsonDocumentToRLMBSON(_options.sort_bson); +} + +- (NSArray> *)sorting { + return RLMConvertBsonDocumentToRLMBSONArray(_options.sort_bson); +} + +- (void)setProjection:(id)projection { + if (projection) { + auto bson = realm::bson::BsonDocument(RLMConvertRLMBSONToBson(projection)); + _options.projection_bson = std::optional(bson); + } else { + _options.projection_bson = realm::util::none; + } +} + +- (void)setSort:(id)sort { + if (sort) { + auto bson = realm::bson::BsonDocument(RLMConvertRLMBSONToBson(sort)); + _options.sort_bson = std::optional(bson); + } else { + _options.sort_bson = realm::util::none; + } +} + +- (void)setSorting:(NSArray> *)sorting { + _options.sort_bson = RLMConvertRLMBSONArrayToBsonDocument(sorting); +} + +- (NSInteger)limit { + return static_cast(_options.limit.value_or(0)); +} + +- (void)setLimit:(NSInteger)limit { + _options.limit = std::optional(limit); +} + +@end diff --git a/Pods/Realm/Realm/RLMLogger.mm b/Pods/Realm/Realm/RLMLogger.mm new file mode 100644 index 0000000..caa7988 --- /dev/null +++ b/Pods/Realm/Realm/RLMLogger.mm @@ -0,0 +1,159 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2023 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMLogger_Private.h" + +#import "RLMUtil.hpp" + +#import + +typedef void (^RLMLoggerFunction)(RLMLogLevel level, NSString *message); + +using namespace realm; +using Logger = realm::util::Logger; +using Level = Logger::Level; + +namespace { +static Level levelForLogLevel(RLMLogLevel logLevel) { + switch (logLevel) { + case RLMLogLevelOff: return Level::off; + case RLMLogLevelFatal: return Level::fatal; + case RLMLogLevelError: return Level::error; + case RLMLogLevelWarn: return Level::warn; + case RLMLogLevelInfo: return Level::info; + case RLMLogLevelDetail: return Level::detail; + case RLMLogLevelDebug: return Level::debug; + case RLMLogLevelTrace: return Level::trace; + case RLMLogLevelAll: return Level::all; + } + REALM_UNREACHABLE(); // Unrecognized log level. +} + +static RLMLogLevel logLevelForLevel(Level logLevel) { + switch (logLevel) { + case Level::off: return RLMLogLevelOff; + case Level::fatal: return RLMLogLevelFatal; + case Level::error: return RLMLogLevelError; + case Level::warn: return RLMLogLevelWarn; + case Level::info: return RLMLogLevelInfo; + case Level::detail: return RLMLogLevelDetail; + case Level::debug: return RLMLogLevelDebug; + case Level::trace: return RLMLogLevelTrace; + case Level::all: return RLMLogLevelAll; + } + REALM_UNREACHABLE(); // Unrecognized log level. +} + +static NSString* levelPrefix(Level logLevel) { + switch (logLevel) { + case Level::off: + case Level::all: return @""; + case Level::trace: return @"Trace"; + case Level::debug: return @"Debug"; + case Level::detail: return @"Detail"; + case Level::info: return @"Info"; + case Level::error: return @"Error"; + case Level::warn: return @"Warning"; + case Level::fatal: return @"Fatal"; + } + REALM_UNREACHABLE(); // Unrecognized log level. +} + +struct CocoaLogger : public Logger { + void do_log(Level level, const std::string& message) override { + NSLog(@"%@: %@", levelPrefix(level), RLMStringDataToNSString(message)); + } +}; + +class CustomLogger : public Logger { +public: + RLMLoggerFunction function; + void do_log(Level level, const std::string& message) override { + @autoreleasepool { + if (function) { + function(logLevelForLevel(level), RLMStringDataToNSString(message)); + } + } + } +}; +} // anonymous namespace + +@implementation RLMLogger { + std::shared_ptr _logger; +} + +typedef void(^LoggerBlock)(RLMLogLevel level, NSString *message); + +- (RLMLogLevel)level { + return logLevelForLevel(_logger->get_level_threshold()); +} + +- (void)setLevel:(RLMLogLevel)level { + _logger->set_level_threshold(levelForLogLevel(level)); +} + ++ (void)initialize { + auto defaultLogger = std::make_shared(); + defaultLogger->set_level_threshold(Level::info); + Logger::set_default_logger(defaultLogger); +} + +- (instancetype)initWithLogger:(std::shared_ptr)logger { + if (self = [self init]) { + self->_logger = logger; + } + return self; +} + +- (instancetype)initWithLevel:(RLMLogLevel)level logFunction:(RLMLogFunction)logFunction { + if (self = [super init]) { + auto logger = std::make_shared(); + logger->set_level_threshold(levelForLogLevel(level)); + logger->function = logFunction; + self->_logger = logger; + } + return self; +} + +- (void)logWithLevel:(RLMLogLevel)logLevel message:(NSString *)message, ... { + auto level = levelForLogLevel(logLevel); + if (_logger->would_log(level)) { + va_list args; + va_start(args, message); + _logger->log(level, "%1", [[NSString alloc] initWithFormat:message arguments:args].UTF8String); + va_end(args); + } +} + +- (void)logLevel:(RLMLogLevel)logLevel message:(NSString *)message { + auto level = levelForLogLevel(logLevel); + if (_logger->would_log(level)) { + _logger->log(level, "%1", message.UTF8String); + } +} + +#pragma mark Global Logger Setter + ++ (instancetype)defaultLogger { + return [[RLMLogger alloc] initWithLogger:Logger::get_default_logger()]; +} + ++ (void)setDefaultLogger:(RLMLogger *)logger { + Logger::set_default_logger(logger->_logger); +} +@end diff --git a/Pods/Realm/Realm/RLMManagedArray.mm b/Pods/Realm/Realm/RLMManagedArray.mm new file mode 100644 index 0000000..44aee52 --- /dev/null +++ b/Pods/Realm/Realm/RLMManagedArray.mm @@ -0,0 +1,549 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMArray_Private.hpp" + +#import "RLMAccessor.hpp" +#import "RLMCollection_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.hpp" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMSchema.h" +#import "RLMSectionedResults_Private.hpp" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import +#import + +#import + +@interface RLMManagedArrayHandoverMetadata : NSObject +@property (nonatomic) NSString *parentClassName; +@property (nonatomic) NSString *key; +@end + +@implementation RLMManagedArrayHandoverMetadata +@end + +@interface RLMManagedArray () +@end + +// +// RLMArray implementation +// +@implementation RLMManagedArray { +@public + realm::List _backingList; + RLMRealm *_realm; + RLMClassInfo *_objectInfo; + RLMClassInfo *_ownerInfo; + std::unique_ptr _observationInfo; +} + +- (RLMManagedArray *)initWithBackingCollection:(realm::List)list + parentInfo:(RLMClassInfo *)parentInfo + property:(__unsafe_unretained RLMProperty *const)property { + if (property.type == RLMPropertyTypeObject) + self = [self initWithObjectClassName:property.objectClassName]; + else + self = [self initWithObjectType:property.type + optional:property.optional]; + if (self) { + _realm = parentInfo->realm; + REALM_ASSERT(list.get_realm() == _realm->_realm); + _backingList = std::move(list); + _ownerInfo = parentInfo; + if (property.type == RLMPropertyTypeObject) + _objectInfo = &parentInfo->linkTargetType(property.index); + else + _objectInfo = _ownerInfo; + _key = property.name; + } + return self; +} + +- (RLMManagedArray *)initWithParent:(__unsafe_unretained RLMObjectBase *const)parentObject + property:(__unsafe_unretained RLMProperty *const)property { + __unsafe_unretained RLMRealm *const realm = parentObject->_realm; + auto col = parentObject->_info->tableColumn(property); + return [self initWithBackingCollection:realm::List(realm->_realm, parentObject->_row, col) + parentInfo:parentObject->_info + property:property]; +} + +- (RLMManagedArray *)initWithParent:(realm::Obj)parent + property:(__unsafe_unretained RLMProperty *const)property + parentInfo:(RLMClassInfo&)info { + auto col = info.tableColumn(property); + return [self initWithBackingCollection:realm::List(info.realm->_realm, parent, col) + parentInfo:&info + property:property]; +} + +void RLMValidateArrayObservationKey(__unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMArray *const array) { + if (![keyPath isEqualToString:RLMInvalidatedKey]) { + @throw RLMException(@"[<%@ %p> addObserver:forKeyPath:options:context:] is not supported. Key path: %@", + [array class], array, keyPath); + } +} + +void RLMEnsureArrayObservationInfo(std::unique_ptr& info, + __unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMArray *const array, + __unsafe_unretained id const observed) { + RLMValidateArrayObservationKey(keyPath, array); + if (!info && array.class == [RLMManagedArray class]) { + auto lv = static_cast(array); + info = std::make_unique(*lv->_ownerInfo, + lv->_backingList.get_parent_object_key(), + observed); + } +} + +template +__attribute__((always_inline)) +static auto translateErrors(Function&& f) { + return translateCollectionError(static_cast(f), @"List"); +} + +template +static void changeArray(__unsafe_unretained RLMManagedArray *const ar, + NSKeyValueChange kind, dispatch_block_t f, IndexSetFactory&& is) { + translateErrors([&] { ar->_backingList.verify_in_transaction(); }); + + RLMObservationTracker tracker(ar->_realm); + tracker.trackDeletions(); + auto obsInfo = RLMGetObservationInfo(ar->_observationInfo.get(), + ar->_backingList.get_parent_object_key(), + *ar->_ownerInfo); + if (obsInfo) { + tracker.willChange(obsInfo, ar->_key, kind, is()); + } + + translateErrors(f); +} + +static void changeArray(__unsafe_unretained RLMManagedArray *const ar, NSKeyValueChange kind, NSUInteger index, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return [NSIndexSet indexSetWithIndex:index]; }); +} + +static void changeArray(__unsafe_unretained RLMManagedArray *const ar, NSKeyValueChange kind, NSRange range, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return [NSIndexSet indexSetWithIndexesInRange:range]; }); +} + +static void changeArray(__unsafe_unretained RLMManagedArray *const ar, NSKeyValueChange kind, NSIndexSet *is, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return is; }); +} + +// +// public method implementations +// +- (RLMRealm *)realm { + return _realm; +} + +- (NSUInteger)count { + return translateErrors([&] { return _backingList.size(); }); +} + +- (BOOL)isInvalidated { + return translateErrors([&] { return !_backingList.is_valid(); }); +} + +- (RLMClassInfo *)objectInfo { + return _objectInfo; +} + + +- (bool)isBackedByList:(realm::List const&)list { + return _backingList == list; +} + +- (BOOL)isEqual:(id)object { + return [object respondsToSelector:@selector(isBackedByList:)] && [object isBackedByList:_backingList]; +} + +- (NSUInteger)hash { + return std::hash()(_backingList); +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + return RLMFastEnumerate(state, len, self); +} + +- (id)objectAtIndex:(NSUInteger)index { + return translateErrors([&] { + RLMAccessorContext context(*_objectInfo); + return _backingList.get(context, index); + }); +} + +static void RLMInsertObject(RLMManagedArray *ar, id object, NSUInteger index) { + RLMArrayValidateMatchingObjectType(ar, object); + if (index == NSUIntegerMax) { + index = translateErrors([&] { return ar->_backingList.size(); }); + } + + changeArray(ar, NSKeyValueChangeInsertion, index, ^{ + RLMAccessorContext context(*ar->_objectInfo); + ar->_backingList.insert(context, index, object); + }); +} + +- (void)addObject:(id)object { + RLMInsertObject(self, object, NSUIntegerMax); +} + +- (void)insertObject:(id)object atIndex:(NSUInteger)index { + RLMInsertObject(self, object, index); +} + +- (void)insertObjects:(id)objects atIndexes:(NSIndexSet *)indexes { + changeArray(self, NSKeyValueChangeInsertion, indexes, ^{ + NSUInteger index = [indexes firstIndex]; + RLMAccessorContext context(*_objectInfo); + for (id obj in objects) { + RLMArrayValidateMatchingObjectType(self, obj); + _backingList.insert(context, index, obj); + index = [indexes indexGreaterThanIndex:index]; + } + }); +} + +- (void)removeObjectAtIndex:(NSUInteger)index { + changeArray(self, NSKeyValueChangeRemoval, index, ^{ + _backingList.remove(index); + }); +} + +- (void)removeObjectsAtIndexes:(NSIndexSet *)indexes { + changeArray(self, NSKeyValueChangeRemoval, indexes, ^{ + [indexes enumerateIndexesWithOptions:NSEnumerationReverse usingBlock:^(NSUInteger idx, BOOL *) { + _backingList.remove(idx); + }]; + }); +} + +- (void)addObjectsFromArray:(NSArray *)array { + changeArray(self, NSKeyValueChangeInsertion, NSMakeRange(self.count, array.count), ^{ + RLMAccessorContext context(*_objectInfo); + for (id obj in array) { + RLMArrayValidateMatchingObjectType(self, obj); + _backingList.add(context, obj); + } + }); +} + +- (void)removeAllObjects { + changeArray(self, NSKeyValueChangeRemoval, NSMakeRange(0, self.count), ^{ + _backingList.remove_all(); + }); +} + +- (void)replaceAllObjectsWithObjects:(NSArray *)objects { + if (auto count = self.count) { + changeArray(self, NSKeyValueChangeRemoval, NSMakeRange(0, count), ^{ + _backingList.remove_all(); + }); + } + if (![objects respondsToSelector:@selector(count)] || !objects.count) { + return; + } + changeArray(self, NSKeyValueChangeInsertion, NSMakeRange(0, objects.count), ^{ + RLMAccessorContext context(*_objectInfo); + _backingList.assign(context, objects); + }); +} + +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)object { + RLMArrayValidateMatchingObjectType(self, object); + changeArray(self, NSKeyValueChangeReplacement, index, ^{ + RLMAccessorContext context(*_objectInfo); + if (index >= _backingList.size()) { + @throw RLMException(@"Index %llu is out of bounds (must be less than %llu).", + (unsigned long long)index, (unsigned long long)_backingList.size()); + } + _backingList.set(context, index, object); + }); +} + +- (void)moveObjectAtIndex:(NSUInteger)sourceIndex toIndex:(NSUInteger)destinationIndex { + auto start = std::min(sourceIndex, destinationIndex); + auto len = std::max(sourceIndex, destinationIndex) - start + 1; + changeArray(self, NSKeyValueChangeReplacement, {start, len}, ^{ + _backingList.move(sourceIndex, destinationIndex); + }); +} + +- (void)exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 { + changeArray(self, NSKeyValueChangeReplacement, ^{ + _backingList.swap(index1, index2); + }, [=] { + NSMutableIndexSet *set = [[NSMutableIndexSet alloc] initWithIndex:index1]; + [set addIndex:index2]; + return set; + }); +} + +- (NSUInteger)indexOfObject:(id)object { + RLMArrayValidateMatchingObjectType(self, object); + return translateErrors([&] { + RLMAccessorContext context(*_objectInfo); + return RLMConvertNotFound(_backingList.find(context, object)); + }); +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath hasPrefix:@"@"]) { + // Delegate KVC collection operators to RLMResults + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo results:_backingList.as_results()]; + return [results valueForKeyPath:keyPath]; + }); + } + return [super valueForKeyPath:keyPath]; +} + +- (id)valueForKey:(NSString *)key { + // Ideally we'd use "@invalidated" for this so that "invalidated" would use + // normal array KVC semantics, but observing @things works very oddly (when + // it's part of a key path, it's triggered automatically when array index + // changes occur, and can't be sent explicitly, but works normally when it's + // the entire key path), and an RLMManagedArray *can't* have objects where + // invalidated is true, so we're not losing much. + return translateErrors([&]() -> id { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @(!_backingList.is_valid()); + } + + _backingList.verify_attached(); + return RLMCollectionValueForKey(_backingList, key, *_objectInfo); + }); +} + +- (void)setValue:(id)value forKey:(NSString *)key { + if ([key isEqualToString:@"self"]) { + RLMArrayValidateMatchingObjectType(self, value); + RLMAccessorContext context(*_objectInfo); + translateErrors([&] { + for (size_t i = 0, count = _backingList.size(); i < count; ++i) { + _backingList.set(context, i, value); + } + }); + return; + } + else if (_type == RLMPropertyTypeObject) { + RLMArrayValidateMatchingObjectType(self, value); + translateErrors([&] { _backingList.verify_in_transaction(); }); + RLMCollectionSetValueForKey(self, key, value); + } + else { + [self setValue:value forUndefinedKey:key]; + } +} + +- (id)minOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingList, _objectInfo, _type, RLMCollectionTypeArray); + auto value = translateErrors([&] { return _backingList.min(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)maxOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingList, _objectInfo, _type, RLMCollectionTypeArray); + auto value = translateErrors([&] { return _backingList.max(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)sumOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingList, _objectInfo, _type, RLMCollectionTypeArray); + return RLMMixedToObjc(translateErrors([&] { return _backingList.sum(column); })); +} + +- (id)averageOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingList, _objectInfo, _type, RLMCollectionTypeArray); + auto value = translateErrors([&] { return _backingList.average(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (void)deleteObjectsFromRealm { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMArray<%@>: only RLMObjects can be deleted.", RLMTypeToString(_type)); + } + // delete all target rows from the realm + RLMObservationTracker tracker(_realm, true); + translateErrors([&] { _backingList.delete_all(); }); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + return translateErrors([&] { + return [RLMResults resultsWithObjectInfo:*_objectInfo + results:_backingList.sort(RLMSortDescriptorsToKeypathArray(properties))]; + }); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo results:_backingList.as_results()]; + return [results distinctResultsUsingKeyPaths:keyPaths]; + }); +} + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Querying is currently only implemented for arrays of Realm Objects"); + } + auto query = RLMPredicateToQuery(predicate, _objectInfo->rlmObjectSchema, _realm.schema, _realm.group); + auto results = translateErrors([&] { return _backingList.filter(std::move(query)); }); + return [RLMResults resultsWithObjectInfo:*_objectInfo results:std::move(results)]; +} + +- (NSUInteger)indexOfObjectWithPredicate:(NSPredicate *)predicate { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Querying is currently only implemented for arrays of Realm Objects"); + } + realm::Query query = RLMPredicateToQuery(predicate, _objectInfo->rlmObjectSchema, + _realm.schema, _realm.group); + + return translateErrors([&] { + return RLMConvertNotFound(_backingList.find(std::move(query))); + }); +} + +- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + size_t c = self.count; + NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:indexes.count]; + NSUInteger i = [indexes firstIndex]; + RLMAccessorContext context(*_objectInfo); + while (i != NSNotFound) { + // Given KVO relies on `objectsAtIndexes` we need to make sure + // that no out of bounds exceptions are generated. This disallows us to mirror + // the exception logic in Foundation, but it is better than nothing. + if (i >= 0 && i < c) { + [result addObject:_backingList.get(context, i)]; + } else { + // silently abort. + return nil; + } + i = [indexes indexGreaterThanIndex:i]; + } + return result; +} + +- (RLMSectionedResults *)sectionedResultsSortedUsingKeyPath:(NSString *)keyPath + ascending:(BOOL)ascending + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + return [[RLMSectionedResults alloc] initWithResults:[self sortedResultsUsingKeyPath:keyPath ascending:ascending] + keyBlock:keyBlock]; +} + +- (RLMSectionedResults *)sectionedResultsUsingSortDescriptors:(NSArray *)sortDescriptors + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + return [[RLMSectionedResults alloc] initWithResults:[self sortedResultsUsingDescriptors:sortDescriptors] + keyBlock:keyBlock]; +} + +- (void)addObserver:(id)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + RLMEnsureArrayObservationInfo(_observationInfo, keyPath, self, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +- (realm::TableView)tableView { + return translateErrors([&] { return _backingList.get_query(); }).find_all(); +} + +- (RLMFastEnumerator *)fastEnumerator { + return translateErrors([&] { + return [[RLMFastEnumerator alloc] initWithBackingCollection:_backingList + collection:self + classInfo:*_objectInfo]; + }); +} + +- (BOOL)isFrozen { + return _realm.isFrozen; +} + +- (instancetype)resolveInRealm:(RLMRealm *)realm { + auto& parentInfo = _ownerInfo->resolve(realm); + return translateErrors([&] { + return [[self.class alloc] initWithBackingCollection:_backingList.freeze(realm->_realm) + parentInfo:&parentInfo + property:parentInfo.rlmObjectSchema[_key]]; + }); +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + return [self resolveInRealm:_realm.freeze]; +} + +- (instancetype)thaw { + if (!self.frozen) { + return self; + } + return [self resolveInRealm:_realm.thaw]; +} + +- (realm::NotificationToken)addNotificationCallback:(id)block +keyPaths:(std::optional>>>&&)keyPaths { + return _backingList.add_notification_callback(RLMWrapCollectionChangeCallback(block, self, false), std::move(keyPaths)); +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _backingList; +} + +- (RLMManagedArrayHandoverMetadata *)objectiveCMetadata { + RLMManagedArrayHandoverMetadata *metadata = [[RLMManagedArrayHandoverMetadata alloc] init]; + metadata.parentClassName = _ownerInfo->rlmObjectSchema.className; + metadata.key = _key; + return metadata; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(RLMManagedArrayHandoverMetadata *)metadata + realm:(RLMRealm *)realm { + auto list = reference.resolve(realm->_realm); + if (!list.is_valid()) { + return nil; + } + RLMClassInfo *parentInfo = &realm->_info[metadata.parentClassName]; + return [[RLMManagedArray alloc] initWithBackingCollection:std::move(list) + parentInfo:parentInfo + property:parentInfo->rlmObjectSchema[metadata.key]]; +} + +@end diff --git a/Pods/Realm/Realm/RLMManagedDictionary.mm b/Pods/Realm/Realm/RLMManagedDictionary.mm new file mode 100644 index 0000000..fa3c1ec --- /dev/null +++ b/Pods/Realm/Realm/RLMManagedDictionary.mm @@ -0,0 +1,539 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2021 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMDictionary_Private.hpp" + +#import "RLMAccessor.hpp" +#import "RLMCollection_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMSchema.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +@interface RLMManagedDictionary () { + @public + realm::object_store::Dictionary _backingCollection; +} +@end + +@implementation RLMDictionaryChange { + realm::DictionaryChangeSet _changes; +} + +- (instancetype)initWithChanges:(realm::DictionaryChangeSet const&)changes { + self = [super init]; + if (self) { + _changes = changes; + } + return self; +} + +static NSArray *toArray(std::vector const& v) { + NSMutableArray *ret = [[NSMutableArray alloc] initWithCapacity:v.size()]; + for (auto& mixed : v) { + [ret addObject:RLMMixedToObjc(mixed)]; + } + return ret; +} + +- (NSArray *)insertions { + return toArray(_changes.insertions); +} + +- (NSArray *)deletions { + return toArray(_changes.deletions); +} + +- (NSArray *)modifications { + return toArray(_changes.modifications); +} + +- (NSString *)description { + return [NSString stringWithFormat:@" insertions: %@, deletions: %@, modifications: %@", + (__bridge void *)self, self.insertions, self.deletions, self.modifications]; +} + +@end + +@interface RLMManagedCollectionHandoverMetadata : NSObject +@property (nonatomic) NSString *parentClassName; +@property (nonatomic) NSString *key; +@end + +@implementation RLMManagedCollectionHandoverMetadata +@end + +@implementation RLMManagedDictionary { +@public + RLMRealm *_realm; + RLMClassInfo *_objectInfo; + RLMClassInfo *_ownerInfo; + std::unique_ptr _observationInfo; +} + +- (RLMManagedDictionary *)initWithBackingCollection:(realm::object_store::Dictionary)dictionary + parentInfo:(RLMClassInfo *)parentInfo + property:(__unsafe_unretained RLMProperty *const)property { + if (property.type == RLMPropertyTypeObject) + self = [self initWithObjectClassName:property.objectClassName keyType:property.dictionaryKeyType]; + else + self = [self initWithObjectType:property.type optional:property.optional keyType:property.dictionaryKeyType]; + if (self) { + _realm = parentInfo->realm; + REALM_ASSERT(dictionary.get_realm() == _realm->_realm); + _backingCollection = std::move(dictionary); + _ownerInfo = parentInfo; + if (property.type == RLMPropertyTypeObject) + _objectInfo = &parentInfo->linkTargetType(property.index); + else + _objectInfo = _ownerInfo; + _key = property.name; + } + return self; +} + +- (RLMManagedDictionary *)initWithParent:(__unsafe_unretained RLMObjectBase *const)parentObject + property:(__unsafe_unretained RLMProperty *const)property { + __unsafe_unretained RLMRealm *const realm = parentObject->_realm; + auto col = parentObject->_info->tableColumn(property); + return [self initWithBackingCollection:realm::object_store::Dictionary(realm->_realm, parentObject->_row, col) + parentInfo:parentObject->_info + property:property]; +} + +- (RLMManagedDictionary *)initWithParent:(realm::Obj)parent + property:(__unsafe_unretained RLMProperty *const)property + parentInfo:(RLMClassInfo&)info { + auto col = info.tableColumn(property); + return [self initWithBackingCollection:realm::object_store::Dictionary(info.realm->_realm, parent, col) + parentInfo:&info + property:property]; +} + +void RLMDictionaryValidateObservationKey(__unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMDictionary *const dictionary) { + if (![keyPath isEqualToString:RLMInvalidatedKey]) { + @throw RLMException(@"[<%@ %p> addObserver:forKeyPath:options:context:] is not supported. Key path: %@", + [dictionary class], dictionary, keyPath); + } +} + +void RLMEnsureDictionaryObservationInfo(std::unique_ptr& info, + __unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMDictionary *const dictionary, + __unsafe_unretained id const observed) { + RLMDictionaryValidateObservationKey(keyPath, dictionary); + if (!info && dictionary.class == [RLMManagedDictionary class]) { + auto lv = static_cast(dictionary); + info = std::make_unique(*lv->_ownerInfo, + lv->_backingCollection.get_parent_object_key(), + observed); + } +} + +// +// validation helpers +// +template +__attribute__((always_inline)) +static auto translateErrors(Function&& f) { + return translateCollectionError(static_cast(f), @"Dictionary"); +} + +static void changeDictionary(__unsafe_unretained RLMManagedDictionary *const dict, + dispatch_block_t f) { + translateErrors([&] { dict->_backingCollection.verify_in_transaction(); }); + + RLMObservationTracker tracker(dict->_realm); + tracker.trackDeletions(); + auto obsInfo = RLMGetObservationInfo(dict->_observationInfo.get(), + dict->_backingCollection.get_parent_object_key(), + *dict->_ownerInfo); + if (obsInfo) { + tracker.willChange(obsInfo, dict->_key); + } + + translateErrors(f); +} + +// +// public method implementations +// +- (RLMRealm *)realm { + return _realm; +} + +- (NSUInteger)count { + return translateErrors([&] { + return _backingCollection.size(); + }); +} + +static NSMutableArray *resultsToArray(RLMClassInfo& info, realm::Results r) { + RLMAccessorContext c(info); + NSMutableArray *array = [NSMutableArray arrayWithCapacity:r.size()]; + for (size_t i = 0, size = r.size(); i < size; ++i) { + [array addObject:r.get(c, i)]; + } + return array; +} + +- (NSArray *)allKeys { + return translateErrors([&] { + return resultsToArray(*_objectInfo, _backingCollection.get_keys()); + }); +} + +- (NSArray *)allValues { + return translateErrors([&] { + return resultsToArray(*_objectInfo, _backingCollection.get_values()); + }); +} + +- (BOOL)isInvalidated { + return translateErrors([&] { return !_backingCollection.is_valid(); }); +} + +- (RLMClassInfo *)objectInfo { + return _objectInfo; +} + +- (bool)isBackedByDictionary:(realm::object_store::Dictionary const&)dictionary { + return _backingCollection == dictionary; +} + +- (BOOL)isEqual:(id)object { + return [object respondsToSelector:@selector(isBackedByDictionary:)] && + [object isBackedByDictionary:_backingCollection]; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + return RLMFastEnumerate(state, len, self); +} + +#pragma mark - Object Retrieval + +- (nullable id)objectForKey:(id)key { + return translateErrors([&]() -> id { + [self.realm verifyThread]; + RLMAccessorContext context(*_objectInfo); + if (auto value = _backingCollection.try_get_any(context.unbox(key))) { + return context.box(*value); + } + return nil; + }); +} + +- (void)setObject:(id)obj forKey:(id)key { + changeDictionary(self, ^{ + RLMAccessorContext c(*_objectInfo); + _backingCollection.insert(c, c.unbox(RLMDictionaryKey(self, key)), + RLMDictionaryValue(self, obj)); + }); +} + +- (void)removeAllObjects { + changeDictionary(self, ^{ + _backingCollection.remove_all(); + }); +} + +- (void)removeObjectsForKeys:(NSArray *)keyArray { + RLMAccessorContext context(*_objectInfo); + changeDictionary(self, [&] { + for (id key in keyArray) { + _backingCollection.try_erase(context.unbox(key)); + } + }); +} + +- (void)removeObjectForKey:(id)key { + changeDictionary(self, ^{ + RLMAccessorContext context(*_objectInfo); + _backingCollection.try_erase(context.unbox(key)); + }); +} + +- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block { + RLMAccessorContext c(*_objectInfo); + BOOL stop = false; + @autoreleasepool { + for (auto&& [key, value] : _backingCollection) { + block(c.box(key), c.box(value), &stop); + if (stop) { + break; + } + } + } +} + +- (void)mergeDictionary:(id)dictionary clear:(bool)clear { + if (!clear && !dictionary) { + return; + } + if (dictionary && ![dictionary respondsToSelector:@selector(enumerateKeysAndObjectsUsingBlock:)]) { + @throw RLMException(@"Cannot %@ object of class '%@'", + clear ? @"set dictionary to" : @"add entries from", + [dictionary className]); + } + + changeDictionary(self, ^{ + RLMAccessorContext c(*_objectInfo); + if (clear) { + _backingCollection.remove_all(); + } + [dictionary enumerateKeysAndObjectsUsingBlock:[&](id key, id value, BOOL *) { + _backingCollection.insert(c, c.unbox(RLMDictionaryKey(self, key)), + RLMDictionaryValue(self, value)); + }]; + }); +} + +- (void)setDictionary:(id)dictionary { + [self mergeDictionary:RLMCoerceToNil(dictionary) clear:true]; +} + +- (void)addEntriesFromDictionary:(id)otherDictionary { + [self mergeDictionary:otherDictionary clear:false]; +} + +#pragma mark - KVC + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath hasPrefix:@"@"]) { + // Delegate KVC collection operators to RLMResults + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo + results:_backingCollection.as_results()]; + return [results valueForKeyPath:keyPath]; + }); + } + return [super valueForKeyPath:keyPath]; +} + +- (id)valueForKey:(NSString *)key { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @(!_backingCollection.is_valid()); + } + return [self objectForKey:key]; +} + +- (void)setValue:(id)value forKey:(nonnull NSString *)key { + [self setObject:value forKeyedSubscript:key]; +} + +- (id)minOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingCollection, _objectInfo, _type, RLMCollectionTypeDictionary); + auto value = translateErrors([&] { + return _backingCollection.as_results().min(column); + }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)maxOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingCollection, _objectInfo, _type, RLMCollectionTypeDictionary); + auto value = translateErrors([&] { + return _backingCollection.as_results().max(column); + }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)sumOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingCollection, _objectInfo, _type, RLMCollectionTypeDictionary); + auto value = translateErrors([&] { + return _backingCollection.as_results().sum(column); + }); + return value ? RLMMixedToObjc(*value) : @0; +} + +- (id)averageOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingCollection, _objectInfo, _type, RLMCollectionTypeDictionary); + auto value = translateErrors([&] { + return _backingCollection.as_results().average(column); + }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (void)deleteObjectsFromRealm { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMManagedDictionary: only RLMObjects can be deleted.", RLMTypeToString(_type), _optional? @"?": @""); + } + // delete all target rows from the realm + RLMObservationTracker tracker(_realm, true); + translateErrors([&] { + for (auto&& [key, value] : _backingCollection) { + _realm.group.get_object(value.get_link()).remove(); + } + _backingCollection.remove_all(); + }); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + return translateErrors([&] { + return [RLMResults resultsWithObjectInfo:*_objectInfo + results:_backingCollection.as_results().sort(RLMSortDescriptorsToKeypathArray(properties))]; + }); +} + +- (RLMResults *)sortedResultsUsingKeyPath:(nonnull NSString *)keyPath ascending:(BOOL)ascending { + return [self sortedResultsUsingDescriptors:@[[RLMSortDescriptor sortDescriptorWithKeyPath:keyPath ascending:ascending]]]; +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo results:_backingCollection.as_results()]; + return [results distinctResultsUsingKeyPaths:keyPaths]; + }); +} + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Querying is currently only implemented for dictionaries of Realm Objects"); + } + auto query = RLMPredicateToQuery(predicate, _objectInfo->rlmObjectSchema, _realm.schema, _realm.group); + auto results = translateErrors([&] { + return _backingCollection.as_results().filter(std::move(query)); + }); + return [RLMResults resultsWithObjectInfo:*_objectInfo results:std::move(results)]; +} + +- (void)addObserver:(id)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + RLMEnsureDictionaryObservationInfo(_observationInfo, keyPath, self, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +- (realm::TableView)tableView { + return translateErrors([&] { + return _backingCollection.as_results().get_query(); + }).find_all(); +} + +- (RLMFastEnumerator *)fastEnumerator { + return translateErrors([&] { + return [[RLMFastEnumerator alloc] initWithBackingDictionary:_backingCollection + dictionary:self + classInfo:*_objectInfo]; + }); +} + +- (BOOL)isFrozen { + return _realm.isFrozen; +} + +- (instancetype)resolveInRealm:(RLMRealm *)realm { + auto& parentInfo = _ownerInfo->resolve(realm); + return translateErrors([&] { + return [[self.class alloc] initWithBackingCollection:_backingCollection.freeze(realm->_realm) + parentInfo:&parentInfo + property:parentInfo.rlmObjectSchema[_key]]; + }); +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + return [self resolveInRealm:_realm.freeze]; +} + +- (instancetype)thaw { + if (!self.frozen) { + return self; + } + return [self resolveInRealm:_realm.thaw]; +} + +namespace { +struct DictionaryCallbackWrapper { + void (^block)(id, RLMDictionaryChange *, NSError *); + RLMManagedDictionary *collection; + realm::TransactionRef previousTransaction; + + DictionaryCallbackWrapper(void (^block)(id, RLMDictionaryChange *, NSError *), RLMManagedDictionary *dictionary) + : block(block) + , collection(dictionary) + , previousTransaction(static_cast(collection.realm.group).duplicate()) + { + } + + void operator()(realm::DictionaryChangeSet const& changes) { + if (changes.deletions.empty() && changes.insertions.empty() && changes.modifications.empty()) { + block(collection, nil, nil); + } + else { + block(collection, [[RLMDictionaryChange alloc] initWithChanges:changes], nil); + } + if (collection.isInvalidated) { + previousTransaction->end_read(); + } + else { + previousTransaction->advance_read(static_cast(collection.realm.group).get_version_of_current_transaction()); + } + } +}; +} // anonymous namespace + +- (realm::NotificationToken)addNotificationCallback:(id)block +keyPaths:(std::optional>>>&&)keyPaths { + return _backingCollection.add_key_based_notification_callback(DictionaryCallbackWrapper{block, self}, + std::move(keyPaths)); +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _backingCollection; +} + +- (RLMManagedCollectionHandoverMetadata *)objectiveCMetadata { + RLMManagedCollectionHandoverMetadata *metadata = [[RLMManagedCollectionHandoverMetadata alloc] init]; + metadata.parentClassName = _ownerInfo->rlmObjectSchema.className; + metadata.key = _key; + return metadata; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(RLMManagedCollectionHandoverMetadata *)metadata + realm:(RLMRealm *)realm { + auto dictionary = reference.resolve(realm->_realm); + if (!dictionary.is_valid()) { + return nil; + } + RLMClassInfo *parentInfo = &realm->_info[metadata.parentClassName]; + return [[RLMManagedDictionary alloc] initWithBackingCollection:std::move(dictionary) + parentInfo:parentInfo + property:parentInfo->rlmObjectSchema[metadata.key]]; +} + +@end diff --git a/Pods/Realm/Realm/RLMManagedSet.mm b/Pods/Realm/Realm/RLMManagedSet.mm new file mode 100644 index 0000000..bc03584 --- /dev/null +++ b/Pods/Realm/Realm/RLMManagedSet.mm @@ -0,0 +1,552 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMSet_Private.hpp" + +#import "RLMAccessor.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSchema.h" +#import "RLMSectionedResults_Private.hpp" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +#import +#import + +@interface RLMManagedSetHandoverMetadata : NSObject +@property (nonatomic) NSString *parentClassName; +@property (nonatomic) NSString *key; +@end + +@implementation RLMManagedSetHandoverMetadata +@end + +@interface RLMManagedSet () +@end + +// +// RLMSet implementation +// +@implementation RLMManagedSet { +@public + realm::object_store::Set _backingSet; + RLMRealm *_realm; + RLMClassInfo *_objectInfo; + RLMClassInfo *_ownerInfo; + std::unique_ptr _observationInfo; +} + +- (RLMManagedSet *)initWithBackingCollection:(realm::object_store::Set)set + parentInfo:(RLMClassInfo *)parentInfo + property:(__unsafe_unretained RLMProperty *const)property { + if (property.type == RLMPropertyTypeObject) + self = [self initWithObjectClassName:property.objectClassName]; + else + self = [self initWithObjectType:property.type + optional:property.optional]; + if (self) { + _realm = parentInfo->realm; + REALM_ASSERT(set.get_realm() == _realm->_realm); + _backingSet = std::move(set); + _ownerInfo = parentInfo; + if (property.type == RLMPropertyTypeObject) + _objectInfo = &parentInfo->linkTargetType(property.index); + else + _objectInfo = _ownerInfo; + _key = property.name; + } + return self; +} + +- (RLMManagedSet *)initWithParent:(__unsafe_unretained RLMObjectBase *const)parentObject + property:(__unsafe_unretained RLMProperty *const)property { + __unsafe_unretained RLMRealm *const realm = parentObject->_realm; + auto col = parentObject->_info->tableColumn(property); + return [self initWithBackingCollection:realm::object_store::Set(realm->_realm, parentObject->_row, col) + parentInfo:parentObject->_info + property:property]; +} + +- (RLMManagedSet *)initWithParent:(realm::Obj)parent + property:(__unsafe_unretained RLMProperty *const)property + parentInfo:(RLMClassInfo&)info { + auto col = info.tableColumn(property); + return [self initWithBackingCollection:realm::object_store::Set(info.realm->_realm, parent, col) + parentInfo:&info + property:property]; +} + +void RLMValidateSetObservationKey(__unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMSet *const set) { + if (![keyPath isEqualToString:RLMInvalidatedKey]) { + @throw RLMException(@"[<%@ %p> addObserver:forKeyPath:options:context:] is not supported. Key path: %@", + [set class], set, keyPath); + } +} + +void RLMEnsureSetObservationInfo(std::unique_ptr& info, + __unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMSet *const set, + __unsafe_unretained id const observed) { + RLMValidateSetObservationKey(keyPath, set); + if (!info && set.class == [RLMManagedSet class]) { + auto lv = static_cast(set); + info = std::make_unique(*lv->_ownerInfo, + lv->_backingSet.get_parent_object_key(), + observed); + } +} + +template +__attribute__((always_inline)) +static auto translateErrors(Function&& f) { + return translateCollectionError(static_cast(f), @"Set"); +} + +static void changeSet(__unsafe_unretained RLMManagedSet *const set, + dispatch_block_t f) { + translateErrors([&] { set->_backingSet.verify_in_transaction(); }); + + RLMObservationTracker tracker(set->_realm, false); + tracker.trackDeletions(); + auto obsInfo = RLMGetObservationInfo(set->_observationInfo.get(), + set->_backingSet.get_parent_object_key(), + *set->_ownerInfo); + if (obsInfo) { + tracker.willChange(obsInfo, set->_key); + } + + translateErrors(f); +} + +// +// public method implementations +// +- (RLMRealm *)realm { + return _realm; +} + +- (NSUInteger)count { + return translateErrors([&] { return _backingSet.size(); }); +} + +- (NSArray *)allObjects { + NSMutableArray *arr = [NSMutableArray new]; + for (id prop : self) { + [arr addObject:prop]; + } + return arr; +} + +- (BOOL)isInvalidated { + return translateErrors([&] { return !_backingSet.is_valid(); }); +} + +- (RLMClassInfo *)objectInfo { + return _objectInfo; +} + + +- (bool)isBackedBySet:(realm::object_store::Set const&)set { + return _backingSet == set; +} + +- (BOOL)isEqual:(id)object { + return [object respondsToSelector:@selector(isBackedBySet:)] && [object isBackedBySet:_backingSet]; +} + +- (NSUInteger)hash { + return std::hash()(_backingSet); +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + return RLMFastEnumerate(state, len, self); +} + +static void RLMInsertObject(RLMManagedSet *set, id object) { + RLMSetValidateMatchingObjectType(set, object); + changeSet(set, ^{ + RLMAccessorContext context(*set->_objectInfo); + set->_backingSet.insert(context, object); + }); +} + +static void RLMRemoveObject(RLMManagedSet *set, id object) { + RLMSetValidateMatchingObjectType(set, object); + changeSet(set, ^{ + RLMAccessorContext context(*set->_objectInfo); + set->_backingSet.remove(context, object); + }); +} + +static void ensureInWriteTransaction(NSString *message, RLMManagedSet *set, RLMManagedSet *otherSet) { + if (!set.realm.inWriteTransaction && !otherSet.realm.inWriteTransaction) { + @throw RLMException(@"Can only perform %@ in a Realm in a write transaction - call beginWriteTransaction on an RLMRealm instance first.", message); + } +} + +- (void)addObject:(id)object { + RLMInsertObject(self, object); +} + +- (void)addObjects:(id)objects { + changeSet(self, ^{ + RLMAccessorContext context(*_objectInfo); + for (id obj in objects) { + RLMSetValidateMatchingObjectType(self, obj); + _backingSet.insert(context, obj); + } + }); +} + +- (void)removeObject:(id)object { + RLMRemoveObject(self, object); +} + +- (void)removeAllObjects { + changeSet(self, ^{ + _backingSet.remove_all(); + }); +} + +- (void)replaceAllObjectsWithObjects:(NSArray *)objects { + changeSet(self, ^{ + RLMAccessorContext context(*_objectInfo); + _backingSet.assign(context, objects); + }); +} + +- (RLMManagedSet *)managedObjectFrom:(RLMSet *)set { + auto managedSet = RLMDynamicCast(set); + if (!managedSet) { + @throw RLMException(@"Right hand side value must be a managed Set."); + } + if (_type != managedSet->_type) { + @throw RLMException(@"Cannot intersect sets of type '%@' and '%@'.", + RLMTypeToString(_type), RLMTypeToString(managedSet->_type)); + } + if (_realm != managedSet->_realm) { + @throw RLMException(@"Cannot insersect sets managed by different Realms."); + } + if (_objectInfo != managedSet->_objectInfo) { + @throw RLMException(@"Cannot intersect sets of type '%@' and '%@'.", + _objectInfo->rlmObjectSchema.className, + managedSet->_objectInfo->rlmObjectSchema.className); + + } + return managedSet; +} + +- (BOOL)isSubsetOfSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + return _backingSet.is_subset_of(rhs->_backingSet); +} + +- (BOOL)intersectsSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + return _backingSet.intersects(rhs->_backingSet); +} + +- (BOOL)containsObject:(id)obj { + RLMSetValidateMatchingObjectType(self, obj); + RLMAccessorContext context(*_objectInfo); + auto r = _backingSet.find(context, obj); + return r != realm::npos; +} + +- (BOOL)isEqualToSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + return [self isEqual:rhs]; +} + +- (void)setSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + ensureInWriteTransaction(@"[RLMSet setSet:]", self, rhs); + changeSet(self, ^{ + RLMAccessorContext context(*_objectInfo); + _backingSet.assign(context, rhs); + }); +} + +- (void)intersectSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + ensureInWriteTransaction(@"[RLMSet intersectSet:]", self, rhs); + changeSet(self, ^{ + _backingSet.assign_intersection(rhs->_backingSet); + }); +} + +- (void)unionSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + ensureInWriteTransaction(@"[RLMSet unionSet:]", self, rhs); + changeSet(self, ^{ + _backingSet.assign_union(rhs->_backingSet); + }); +} + +- (void)minusSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + ensureInWriteTransaction(@"[RLMSet minusSet:]", self, rhs); + changeSet(self, ^{ + _backingSet.assign_difference(rhs->_backingSet); + }); +} + +- (id)objectAtIndex:(NSUInteger)index { + return translateErrors([&] { + RLMAccessorContext context(*_objectInfo); + return _backingSet.get(context, index); + }); +} + +- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + size_t count = self.count; + NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:indexes.count]; + RLMAccessorContext context(*_objectInfo); + for (NSUInteger i = indexes.firstIndex; i != NSNotFound; i = [indexes indexGreaterThanIndex:i]) { + if (i >= count) { + return nil; + } + [result addObject:_backingSet.get(context, i)]; + } + return result; +} + +- (id)firstObject { + return translateErrors([&] { + RLMAccessorContext context(*_objectInfo); + return _backingSet.size() ? _backingSet.get(context, 0) : nil; + }); +} + +- (id)lastObject { + return translateErrors([&] { + RLMAccessorContext context(*_objectInfo); + size_t size = _backingSet.size(); + return size ? _backingSet.get(context, size - 1) : nil; + }); +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath hasPrefix:@"@"]) { + // Delegate KVC collection operators to RLMResults + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo results:_backingSet.as_results()]; + return [results valueForKeyPath:keyPath]; + }); + } + return [super valueForKeyPath:keyPath]; +} + +- (id)valueForKey:(NSString *)key { + // Ideally we'd use "@invalidated" for this so that "invalidated" would use + // normal array KVC semantics, but observing @things works very oddly (when + // it's part of a key path, it's triggered automatically when array index + // changes occur, and can't be sent explicitly, but works normally when it's + // the entire key path), and an RLMManagedSet *can't* have objects where + // invalidated is true, so we're not losing much. + return translateErrors([&]() -> id { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @(!_backingSet.is_valid()); + } + + _backingSet.verify_attached(); + return [NSSet setWithArray:RLMCollectionValueForKey(_backingSet, key, *_objectInfo)]; + }); + return nil; +} + +- (void)setValue:(id)value forKey:(NSString *)key { + if ([key isEqualToString:@"self"]) { + RLMSetValidateMatchingObjectType(self, value); + RLMAccessorContext context(*_objectInfo); + translateErrors([&] { + _backingSet.remove_all(); + _backingSet.insert(context, value); + return; + }); + } else if (_type == RLMPropertyTypeObject) { + RLMSetValidateMatchingObjectType(self, value); + translateErrors([&] { _backingSet.verify_in_transaction(); }); + RLMCollectionSetValueForKey(self, key, value); + } + else { + [self setValue:value forUndefinedKey:key]; + } +} + +- (id)minOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingSet, _objectInfo, _type, RLMCollectionTypeSet); + auto value = translateErrors([&] { return _backingSet.min(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)maxOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingSet, _objectInfo, _type, RLMCollectionTypeSet); + auto value = translateErrors([&] { return _backingSet.max(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)sumOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingSet, _objectInfo, _type, RLMCollectionTypeSet); + return RLMMixedToObjc(translateErrors([&] { return _backingSet.sum(column); })); +} + +- (id)averageOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingSet, _objectInfo, _type, RLMCollectionTypeSet); + auto value = translateErrors([&] { return _backingSet.average(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (void)deleteObjectsFromRealm { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMSet<%@>: only RLMObjects can be deleted.", RLMTypeToString(_type)); + } + // delete all target rows from the realm + RLMObservationTracker tracker(_realm, true); + translateErrors([&] { _backingSet.delete_all(); }); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + return translateErrors([&] { + return [RLMResults resultsWithObjectInfo:*_objectInfo + results:_backingSet.sort(RLMSortDescriptorsToKeypathArray(properties))]; + }); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo results:_backingSet.as_results()]; + return [results distinctResultsUsingKeyPaths:keyPaths]; + }); +} + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Querying is currently only implemented for sets of Realm Objects"); + } + auto query = RLMPredicateToQuery(predicate, _objectInfo->rlmObjectSchema, _realm.schema, _realm.group); + auto results = translateErrors([&] { return _backingSet.filter(std::move(query)); }); + return [RLMResults resultsWithObjectInfo:*_objectInfo results:std::move(results)]; +} + +- (RLMSectionedResults *)sectionedResultsSortedUsingKeyPath:(NSString *)keyPath + ascending:(BOOL)ascending + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + return [[RLMSectionedResults alloc] initWithResults:[self sortedResultsUsingKeyPath:keyPath ascending:ascending] + keyBlock:keyBlock]; +} + +- (RLMSectionedResults *)sectionedResultsUsingSortDescriptors:(NSArray *)sortDescriptors + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + return [[RLMSectionedResults alloc] initWithResults:[self sortedResultsUsingDescriptors:sortDescriptors] + keyBlock:keyBlock]; +} + +- (void)addObserver:(id)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + RLMEnsureSetObservationInfo(_observationInfo, keyPath, self, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +- (RLMFastEnumerator *)fastEnumerator { + return translateErrors([&] { + return [[RLMFastEnumerator alloc] initWithBackingCollection:_backingSet + collection:self + classInfo:*_objectInfo]; + }); +} + +- (realm::TableView)tableView { + return translateErrors([&] { return _backingSet.get_query(); }).find_all(); +} + +- (BOOL)isFrozen { + return _realm.isFrozen; +} + +- (instancetype)resolveInRealm:(RLMRealm *)realm { + auto& parentInfo = _ownerInfo->resolve(realm); + return translateErrors([&] { + return [[self.class alloc] initWithBackingCollection:_backingSet.freeze(realm->_realm) + parentInfo:&parentInfo + property:parentInfo.rlmObjectSchema[_key]]; + }); +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + return [self resolveInRealm:_realm.freeze]; +} + +- (instancetype)thaw { + if (!self.frozen) { + return self; + } + return [self resolveInRealm:_realm.thaw]; +} + +- (realm::NotificationToken)addNotificationCallback:(id)block +keyPaths:(std::optional>>>&&)keyPaths { + return _backingSet.add_notification_callback(RLMWrapCollectionChangeCallback(block, self, false), std::move(keyPaths)); +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _backingSet; +} + +- (RLMManagedSetHandoverMetadata *)objectiveCMetadata { + RLMManagedSetHandoverMetadata *metadata = [[RLMManagedSetHandoverMetadata alloc] init]; + metadata.parentClassName = _ownerInfo->rlmObjectSchema.className; + metadata.key = _key; + return metadata; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(RLMManagedSetHandoverMetadata *)metadata + realm:(RLMRealm *)realm { + auto set = reference.resolve(realm->_realm); + if (!set.is_valid()) { + return nil; + } + RLMClassInfo *parentInfo = &realm->_info[metadata.parentClassName]; + return [[RLMManagedSet alloc] initWithBackingCollection:std::move(set) + parentInfo:parentInfo + property:parentInfo->rlmObjectSchema[metadata.key]]; +} + +@end + diff --git a/Pods/Realm/Realm/RLMMigration.mm b/Pods/Realm/Realm/RLMMigration.mm new file mode 100644 index 0000000..bddf6d8 --- /dev/null +++ b/Pods/Realm/Realm/RLMMigration.mm @@ -0,0 +1,166 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMMigration_Private.h" + +#import "RLMAccessor.h" +#import "RLMObject_Private.h" +#import "RLMObject_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMProperty_Private.h" +#import "RLMRealm_Dynamic.h" +#import "RLMRealm_Private.hpp" +#import "RLMResults_Private.hpp" +#import "RLMSchema_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import +#import + +using namespace realm; + +@implementation RLMMigration { + realm::Schema *_schema; +} + +- (instancetype)initWithRealm:(RLMRealm *)realm oldRealm:(RLMRealm *)oldRealm schema:(realm::Schema &)schema { + self = [super init]; + if (self) { + _realm = realm; + _oldRealm = oldRealm; + _schema = &schema; + } + return self; +} + +- (RLMSchema *)oldSchema { + return self.oldRealm.schema; +} + +- (RLMSchema *)newSchema { + return self.realm.schema; +} + +- (void)enumerateObjects:(NSString *)className block:(__attribute__((noescape)) RLMObjectMigrationBlock)block { + RLMResults *objects = [_realm.schema schemaForClassName:className] ? [_realm allObjects:className] : nil; + RLMResults *oldObjects = [_oldRealm.schema schemaForClassName:className] ? [_oldRealm allObjects:className] : nil; + + // For whatever reason if this is a newly added table we enumerate the + // objects in it, while in all other cases we enumerate only the existing + // objects. It's unclear how this could be useful, but changing it would + // also be a pointless breaking change and it's unlikely to be hurting anyone. + if (objects && !oldObjects) { + for (RLMObject *object in objects) { + @autoreleasepool { + block(nil, object); + } + } + return; + } + + // If a table will be deleted it can still be enumerated during the migration + // so that data can be saved or transfered to other tables if necessary. + if (!objects && oldObjects) { + for (RLMObject *oldObject in oldObjects) { + @autoreleasepool { + block(oldObject, nil); + } + } + return; + } + + if (oldObjects.count == 0 || objects.count == 0) { + return; + } + + auto& info = _realm->_info[className]; + for (RLMObject *oldObject in oldObjects) { + @autoreleasepool { + Obj newObj; + try { + newObj = info.table()->get_object(oldObject->_row.get_key()); + } + catch (KeyNotFound const&) { + continue; + } + block(oldObject, (id)RLMCreateObjectAccessor(info, std::move(newObj))); + } + } +} + +- (void)execute:(RLMMigrationBlock)block objectClass:(Class)dynamicObjectClass { + if (!dynamicObjectClass) { + dynamicObjectClass = RLMDynamicObject.class; + } + @autoreleasepool { + // disable all primary keys for migration and use DynamicObject for all types + for (RLMObjectSchema *objectSchema in _realm.schema.objectSchema) { + objectSchema.accessorClass = dynamicObjectClass; + objectSchema.primaryKeyProperty.isPrimary = NO; + } + for (RLMObjectSchema *objectSchema in _oldRealm.schema.objectSchema) { + objectSchema.accessorClass = dynamicObjectClass; + } + + block(self, _oldRealm->_realm->schema_version()); + + _oldRealm = nil; + _realm = nil; + } +} + +- (RLMObject *)createObject:(NSString *)className withValue:(id)value { + return [_realm createObject:className withValue:value]; +} + +- (RLMObject *)createObject:(NSString *)className withObject:(id)object { + return [self createObject:className withValue:object]; +} + +- (void)deleteObject:(RLMObject *)object { + [_realm deleteObject:object]; +} + +- (BOOL)deleteDataForClassName:(NSString *)name { + if (!name) { + return false; + } + + TableRef table = ObjectStore::table_for_object_type(_realm.group, name.UTF8String); + if (!table) { + return false; + } + if ([_realm.schema schemaForClassName:name]) { + table->clear(); + } + else { + _realm.group.remove_table(table->get_key()); + } + + return true; +} + +- (void)renamePropertyForClass:(NSString *)className oldName:(NSString *)oldName newName:(NSString *)newName { + realm::ObjectStore::rename_property(_realm.group, *_schema, className.UTF8String, + oldName.UTF8String, newName.UTF8String); +} + +@end diff --git a/Pods/Realm/Realm/RLMMongoClient.mm b/Pods/Realm/Realm/RLMMongoClient.mm new file mode 100644 index 0000000..1867a54 --- /dev/null +++ b/Pods/Realm/Realm/RLMMongoClient.mm @@ -0,0 +1,67 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMMongoClient_Private.hpp" + +#import "RLMMongoDatabase_Private.hpp" +#import "RLMMongoCollection_Private.h" +#import "RLMApp_Private.hpp" + +#import +#import +#import + +@implementation RLMMongoClient + +- (instancetype)initWithUser:(RLMUser *)user serviceName:(NSString *)serviceName { + if (self = [super init]) { + _user = user; + _name = serviceName; + } + return self; +} + +- (RLMMongoDatabase *)databaseWithName:(NSString *)name { + return [[RLMMongoDatabase alloc] initWithUser:self.user + serviceName:self.name + databaseName:name]; +} + +@end + +@implementation RLMMongoDatabase + +- (instancetype)initWithUser:(RLMUser *)user + serviceName:(NSString *)serviceName + databaseName:(NSString *)databaseName { + if (self = [super init]) { + _user = user; + _serviceName = serviceName; + _name = databaseName; + } + return self; +} + +- (RLMMongoCollection *)collectionWithName:(NSString *)name { + return [[RLMMongoCollection alloc] initWithUser:self.user + serviceName:self.serviceName + databaseName:self.name + collectionName:name]; +} + +@end diff --git a/Pods/Realm/Realm/RLMMongoCollection.mm b/Pods/Realm/Realm/RLMMongoCollection.mm new file mode 100644 index 0000000..ee3bfa4 --- /dev/null +++ b/Pods/Realm/Realm/RLMMongoCollection.mm @@ -0,0 +1,440 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMMongoCollection_Private.h" + +#import "RLMApp_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMError_Private.hpp" +#import "RLMFindOneAndModifyOptions_Private.hpp" +#import "RLMFindOptions_Private.hpp" +#import "RLMNetworkTransport_Private.hpp" +#import "RLMUpdateResult_Private.hpp" +#import "RLMUser_Private.hpp" + +#import +#import +#import + +__attribute__((objc_direct_members)) +@implementation RLMChangeStream { +@public + realm::app::WatchStream _watchStream; + id _subscriber; + __weak NSURLSession *_session; + void (^_schedule)(dispatch_block_t); +} + +- (instancetype)initWithChangeEventSubscriber:(id)subscriber + scheduler:(void (^)(dispatch_block_t))scheduler { + if (self = [super init]) { + _subscriber = subscriber; + _schedule = scheduler; + } + return self; +} + +- (void)didCloseWithError:(NSError *)error { + _schedule(^{ + [_subscriber changeStreamDidCloseWithError:error]; + }); +} + +- (void)didOpen { + _schedule(^{ + [_subscriber changeStreamDidOpen:self]; + }); +} + +- (void)didReceiveError:(nonnull NSError *)error { + _schedule(^{ + [_subscriber changeStreamDidReceiveError:error]; + }); +} + +- (void)didReceiveEvent:(nonnull NSData *)event { + if (_watchStream.state() == realm::app::WatchStream::State::NEED_DATA) { + [event enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *) { + _watchStream.feed_buffer(std::string_view(static_cast(bytes), byteRange.length)); + }]; + } + + while (_watchStream.state() == realm::app::WatchStream::State::HAVE_EVENT) { + id event = RLMConvertBsonToRLMBSON(_watchStream.next_event()); + _schedule(^{ + [_subscriber changeStreamDidReceiveChangeEvent:event]; + }); + } + + if (_watchStream.state() == realm::app::WatchStream::State::HAVE_ERROR) { + [self didReceiveError:makeError(_watchStream.error())]; + } +} + +- (void)attachURLSession:(NSURLSession *)urlSession { + _session = urlSession; +} + +- (void)close { + [_session invalidateAndCancel]; +} +@end + +static realm::bson::BsonDocument toBsonDocument(id bson) { + return realm::bson::BsonDocument(RLMConvertRLMBSONToBson(bson)); +} +static realm::bson::BsonArray toBsonArray(id bson) { + return realm::bson::BsonArray(RLMConvertRLMBSONToBson(bson)); +} + +__attribute__((objc_direct_members)) +@interface RLMMongoCollection () +@property (nonatomic, strong) RLMUser *user; +@property (nonatomic, strong) NSString *serviceName; +@property (nonatomic, strong) NSString *databaseName; +@end + +__attribute__((objc_direct_members)) +@implementation RLMMongoCollection +- (instancetype)initWithUser:(RLMUser *)user + serviceName:(NSString *)serviceName + databaseName:(NSString *)databaseName + collectionName:(NSString *)collectionName { + if (self = [super init]) { + _user = user; + _serviceName = serviceName; + _databaseName = databaseName; + _name = collectionName; + } + return self; +} + +- (realm::app::MongoCollection)collection:(NSString *)name { + return _user._syncUser->mongo_client(self.serviceName.UTF8String) + .db(self.databaseName.UTF8String).collection(name.UTF8String); +} + +- (realm::app::MongoCollection)collection { + return [self collection:self.name]; +} + +- (void)findWhere:(NSDictionary> *)document + options:(RLMFindOptions *)options + completion:(RLMMongoFindBlock)completion { + self.collection.find(toBsonDocument(document), [options _findOptions], + [completion](std::optional documents, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + completion((NSArray> *> *)RLMConvertBsonToRLMBSON(*documents), nil); + }); +} + +- (void)findWhere:(NSDictionary> *)document + completion:(RLMMongoFindBlock)completion { + [self findWhere:document options:[[RLMFindOptions alloc] init] completion:completion]; +} + +- (void)findOneDocumentWhere:(NSDictionary> *)document + options:(RLMFindOptions *)options + completion:(RLMMongoFindOneBlock)completion { + self.collection.find_one(toBsonDocument(document), [options _findOptions], + [completion](std::optional document, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + if (document) { + completion((NSDictionary> *)RLMConvertBsonToRLMBSON(*document), nil); + } else { + completion(nil, nil); + } + }); +} + +- (void)findOneDocumentWhere:(NSDictionary> *)document + completion:(RLMMongoFindOneBlock)completion { + [self findOneDocumentWhere:document options:[[RLMFindOptions alloc] init] completion:completion]; +} + +- (void)insertOneDocument:(NSDictionary> *)document + completion:(RLMMongoInsertBlock)completion { + self.collection.insert_one(toBsonDocument(document), + [completion](std::optional objectId, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + completion(RLMConvertBsonToRLMBSON(*objectId), nil); + }); +} + +- (void)insertManyDocuments:(NSArray> *> *)documents + completion:(RLMMongoInsertManyBlock)completion { + self.collection.insert_many(toBsonArray(documents), + [completion](std::vector insertedIds, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + NSMutableArray *insertedArr = [[NSMutableArray alloc] initWithCapacity:insertedIds.size()]; + for (auto& objectId : insertedIds) { + [insertedArr addObject:RLMConvertBsonToRLMBSON(objectId)]; + } + completion(insertedArr, nil); + }); +} + +- (void)aggregateWithPipeline:(NSArray> *> *)pipeline + completion:(RLMMongoFindBlock)completion { + self.collection.aggregate(toBsonArray(pipeline), + [completion](std::optional documents, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + completion((NSArray *)RLMConvertBsonToRLMBSON(*documents), nil); + }); +} + +- (void)countWhere:(NSDictionary> *)document + limit:(NSInteger)limit + completion:(RLMMongoCountBlock)completion { + self.collection.count(toBsonDocument(document), limit, + [completion](uint64_t count, + std::optional error) { + if (error) { + return completion(0, makeError(*error)); + } + completion(static_cast(count), nil); + }); +} + +- (void)countWhere:(NSDictionary> *)document + completion:(RLMMongoCountBlock)completion { + [self countWhere:document limit:0 completion:completion]; +} + +- (void)deleteOneDocumentWhere:(NSDictionary> *)document + completion:(RLMMongoCountBlock)completion { + self.collection.delete_one(toBsonDocument(document), + [completion](uint64_t count, + std::optional error) { + if (error) { + return completion(0, makeError(*error)); + } + completion(static_cast(count), nil); + }); +} + +- (void)deleteManyDocumentsWhere:(NSDictionary> *)document + completion:(RLMMongoCountBlock)completion { + self.collection.delete_many(toBsonDocument(document), + [completion](uint64_t count, + std::optional error) { + if (error) { + return completion(0, makeError(*error)); + } + completion(static_cast(count), nil); + }); +} + +- (void)updateOneDocumentWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + upsert:(BOOL)upsert + completion:(RLMMongoUpdateBlock)completion { + self.collection.update_one(toBsonDocument(filterDocument), toBsonDocument(updateDocument), + upsert, + [completion](realm::app::MongoCollection::UpdateResult result, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + completion([[RLMUpdateResult alloc] initWithUpdateResult:result], nil); + }); +} + +- (void)updateOneDocumentWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + completion:(RLMMongoUpdateBlock)completion { + [self updateOneDocumentWhere:filterDocument + updateDocument:updateDocument + upsert:NO + completion:completion]; +} + +- (void)updateManyDocumentsWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + upsert:(BOOL)upsert + completion:(RLMMongoUpdateBlock)completion { + self.collection.update_many(toBsonDocument(filterDocument), toBsonDocument(updateDocument), + upsert, + [completion](realm::app::MongoCollection::UpdateResult result, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + completion([[RLMUpdateResult alloc] initWithUpdateResult:result], nil); + }); +} + +- (void)updateManyDocumentsWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + completion:(RLMMongoUpdateBlock)completion { + [self updateManyDocumentsWhere:filterDocument + updateDocument:updateDocument + upsert:NO + completion:completion]; +} + +- (void)findOneAndUpdateWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + options:(RLMFindOneAndModifyOptions *)options + completion:(RLMMongoFindOneBlock)completion { + self.collection.find_one_and_update(toBsonDocument(filterDocument), toBsonDocument(updateDocument), + [options _findOneAndModifyOptions], + [completion](std::optional document, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + + return completion((NSDictionary *)RLMConvertBsonDocumentToRLMBSON(document), nil); + }); +} + +- (void)findOneAndUpdateWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + completion:(RLMMongoFindOneBlock)completion { + [self findOneAndUpdateWhere:filterDocument + updateDocument:updateDocument + options:[[RLMFindOneAndModifyOptions alloc] init] + completion:completion]; +} + +- (void)findOneAndReplaceWhere:(NSDictionary> *)filterDocument + replacementDocument:(NSDictionary> *)replacementDocument + options:(RLMFindOneAndModifyOptions *)options + completion:(RLMMongoFindOneBlock)completion { + self.collection.find_one_and_replace(toBsonDocument(filterDocument), toBsonDocument(replacementDocument), + [options _findOneAndModifyOptions], + [completion](std::optional document, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + + return completion((NSDictionary *)RLMConvertBsonDocumentToRLMBSON(document), nil); + }); +} + +- (void)findOneAndReplaceWhere:(NSDictionary> *)filterDocument + replacementDocument:(NSDictionary> *)replacementDocument + completion:(RLMMongoFindOneBlock)completion { + [self findOneAndReplaceWhere:filterDocument + replacementDocument:replacementDocument + options:[[RLMFindOneAndModifyOptions alloc] init] + completion:completion]; +} + +- (void)findOneAndDeleteWhere:(NSDictionary> *)filterDocument + options:(RLMFindOneAndModifyOptions *)options + completion:(RLMMongoDeleteBlock)completion { + self.collection.find_one_and_delete(toBsonDocument(filterDocument), + [options _findOneAndModifyOptions], + [completion](std::optional document, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + + return completion((NSDictionary *)RLMConvertBsonDocumentToRLMBSON(document), nil); + }); +} + +- (void)findOneAndDeleteWhere:(NSDictionary> *)filterDocument + completion:(RLMMongoDeleteBlock)completion { + [self findOneAndDeleteWhere:filterDocument + options:[[RLMFindOneAndModifyOptions alloc] init] + completion:completion]; +} + +- (RLMChangeStream *)watchWithDelegate:(id)delegate + delegateQueue:(nullable dispatch_queue_t)delegateQueue { + return [self watchWithMatchFilter:nil + idFilter:nil + delegate:delegate + delegateQueue:delegateQueue]; +} + +- (RLMChangeStream *)watchWithFilterIds:(NSArray *)filterIds + delegate:(id)delegate + delegateQueue:(nullable dispatch_queue_t)delegateQueue { + return [self watchWithMatchFilter:nil + idFilter:filterIds + delegate:delegate + delegateQueue:delegateQueue]; +} + +- (RLMChangeStream *)watchWithMatchFilter:(NSDictionary> *)matchFilter + delegate:(id)delegate + delegateQueue:(nullable dispatch_queue_t)delegateQueue { + return [self watchWithMatchFilter:matchFilter + idFilter:nil + delegate:delegate + delegateQueue:delegateQueue]; +} + +- (RLMChangeStream *)watchWithMatchFilter:(nullable id)matchFilter + idFilter:(nullable id)idFilter + delegate:(id)delegate + delegateQueue:(nullable dispatch_queue_t)queue { + queue = queue ?: dispatch_get_main_queue(); + return [self watchWithMatchFilter:matchFilter + idFilter:idFilter + delegate:delegate + scheduler:^(dispatch_block_t block) { dispatch_async(queue, block); }]; +} + +- (RLMChangeStream *)watchWithMatchFilter:(nullable id)matchFilter + idFilter:(nullable id)idFilter + delegate:(id)delegate + scheduler:(void (^)(dispatch_block_t))scheduler { + realm::bson::BsonDocument baseArgs = { + {"database", self.databaseName.UTF8String}, + {"collection", self.name.UTF8String} + }; + + if (matchFilter) { + baseArgs["filter"] = RLMConvertRLMBSONToBson(matchFilter); + } + if (idFilter) { + baseArgs["ids"] = RLMConvertRLMBSONToBson(idFilter); + } + auto args = realm::bson::BsonArray{baseArgs}; + auto app = self.user.app._realmApp; + auto request = app->make_streaming_request(app->current_user(), "watch", args, + std::optional(self.serviceName.UTF8String)); + auto changeStream = [[RLMChangeStream alloc] initWithChangeEventSubscriber:delegate scheduler:scheduler]; + RLMNetworkTransport *transport = self.user.app.configuration.transport; + RLMRequest *rlmRequest = RLMRequestFromRequest(request); + changeStream->_session = [transport doStreamRequest:rlmRequest eventSubscriber:changeStream]; + return changeStream; +} +@end diff --git a/Pods/Realm/Realm/RLMNetworkTransport.mm b/Pods/Realm/Realm/RLMNetworkTransport.mm new file mode 100644 index 0000000..edd12cf --- /dev/null +++ b/Pods/Realm/Realm/RLMNetworkTransport.mm @@ -0,0 +1,238 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMNetworkTransport_Private.hpp" + +#import "RLMApp.h" +#import "RLMError.h" +#import "RLMRealmConfiguration.h" +#import "RLMSyncUtil_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import + +using namespace realm; + +static_assert((int)RLMHTTPMethodGET == (int)app::HttpMethod::get); +static_assert((int)RLMHTTPMethodPOST == (int)app::HttpMethod::post); +static_assert((int)RLMHTTPMethodPUT == (int)app::HttpMethod::put); +static_assert((int)RLMHTTPMethodPATCH == (int)app::HttpMethod::patch); +static_assert((int)RLMHTTPMethodDELETE == (int)app::HttpMethod::del); + +#pragma mark RLMSessionDelegate + +@interface RLMSessionDelegate : NSObject ++ (instancetype)delegateWithCompletion:(RLMNetworkTransportCompletionBlock)completion; +@end + +NSString * const RLMHTTPMethodToNSString[] = { + [RLMHTTPMethodGET] = @"GET", + [RLMHTTPMethodPOST] = @"POST", + [RLMHTTPMethodPUT] = @"PUT", + [RLMHTTPMethodPATCH] = @"PATCH", + [RLMHTTPMethodDELETE] = @"DELETE" +}; + +@implementation RLMRequest +@end + +@implementation RLMResponse +@end + +@interface RLMEventSessionDelegate : NSObject ++ (instancetype)delegateWithEventSubscriber:(id)subscriber; +@end; + +@implementation RLMNetworkTransport + +- (void)sendRequestToServer:(RLMRequest *)request + completion:(RLMNetworkTransportCompletionBlock)completionBlock { + // Create the request + NSURL *requestURL = [[NSURL alloc] initWithString: request.url]; + NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:requestURL]; + urlRequest.HTTPMethod = RLMHTTPMethodToNSString[request.method]; + if (![urlRequest.HTTPMethod isEqualToString:@"GET"]) { + urlRequest.HTTPBody = [request.body dataUsingEncoding:NSUTF8StringEncoding]; + } + urlRequest.timeoutInterval = request.timeout; + + for (NSString *key in request.headers) { + [urlRequest addValue:request.headers[key] forHTTPHeaderField:key]; + } + id delegate = [RLMSessionDelegate delegateWithCompletion:completionBlock]; + auto session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.defaultSessionConfiguration + delegate:delegate delegateQueue:nil]; + + // Add the request to a task and start it + [[session dataTaskWithRequest:urlRequest] resume]; + // Tell the session to destroy itself once it's done with the request + [session finishTasksAndInvalidate]; +} + +- (NSURLSession *)doStreamRequest:(nonnull RLMRequest *)request + eventSubscriber:(nonnull id)subscriber { + NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + sessionConfig.timeoutIntervalForRequest = 30; + sessionConfig.timeoutIntervalForResource = INT_MAX; + sessionConfig.HTTPAdditionalHeaders = @{ + @"Content-Type": @"text/event-stream", + @"Cache": @"no-cache", + @"Accept": @"text/event-stream" + }; + id delegate = [RLMEventSessionDelegate delegateWithEventSubscriber:subscriber]; + auto session = [NSURLSession sessionWithConfiguration:sessionConfig + delegate:delegate + delegateQueue:nil]; + NSURL *url = [[NSURL alloc] initWithString:request.url]; + [[session dataTaskWithURL:url] resume]; + return session; +} + +RLMRequest *RLMRequestFromRequest(realm::app::Request const& request) { + RLMRequest *rlmRequest = [RLMRequest new]; + NSMutableDictionary *headersDict = [NSMutableDictionary new]; + for (auto &[key, value] : request.headers) { + headersDict[@(key.c_str())] = @(value.c_str()); + } + rlmRequest.headers = headersDict; + rlmRequest.method = static_cast(request.method); + rlmRequest.timeout = request.timeout_ms; + rlmRequest.url = @(request.url.c_str()); + rlmRequest.body = @(request.body.c_str()); + return rlmRequest; +} + +@end + +#pragma mark RLMSessionDelegate + +@implementation RLMSessionDelegate { + NSData *_data; + RLMNetworkTransportCompletionBlock _completionBlock; +} + ++ (instancetype)delegateWithCompletion:(RLMNetworkTransportCompletionBlock)completion { + RLMSessionDelegate *delegate = [RLMSessionDelegate new]; + delegate->_completionBlock = completion; + return delegate; +} + +- (void)URLSession:(__unused NSURLSession *)session + dataTask:(__unused NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + if (!_data) { + _data = data; + return; + } + if (![_data respondsToSelector:@selector(appendData:)]) { + _data = [_data mutableCopy]; + } + [(id)_data appendData:data]; +} + +- (void)URLSession:(__unused NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error +{ + RLMResponse *response = [RLMResponse new]; + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) task.response; + response.headers = httpResponse.allHeaderFields; + response.httpStatusCode = httpResponse.statusCode; + + if (error) { + response.body = error.localizedDescription; + response.customStatusCode = error.code; + return _completionBlock(response); + } + + response.body = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding]; + + _completionBlock(response); +} + +@end + +@implementation RLMEventSessionDelegate { + id _subscriber; + bool _hasOpened; +} + ++ (instancetype)delegateWithEventSubscriber:(id)subscriber { + RLMEventSessionDelegate *delegate = [RLMEventSessionDelegate new]; + delegate->_subscriber = subscriber; + return delegate; +} + +- (void)URLSession:(__unused NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + if (!_hasOpened) { + _hasOpened = true; + [_subscriber didOpen]; + } + + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)dataTask.response; + if (httpResponse.statusCode == 200) { + return [_subscriber didReceiveEvent:data]; + } + + NSString *errorStatus = [NSString stringWithFormat:@"URLSession HTTP error code: %ld", + (long)httpResponse.statusCode]; + NSError *error = [NSError errorWithDomain:RLMAppErrorDomain + code:RLMAppErrorHttpRequestFailed + userInfo:@{NSLocalizedDescriptionKey: errorStatus, + RLMHTTPStatusCodeKey: @(httpResponse.statusCode), + NSURLErrorFailingURLErrorKey: dataTask.currentRequest.URL}]; + return [_subscriber didCloseWithError:error]; +} + +- (void)URLSession:(__unused NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error +{ + RLMResponse *response = [RLMResponse new]; + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response; + response.headers = httpResponse.allHeaderFields; + response.httpStatusCode = httpResponse.statusCode; + + // -999 indicates that the session was cancelled. + if (error && (error.code != -999)) { + response.body = [error localizedDescription]; + return [_subscriber didCloseWithError:error]; + } + if (error && (error.code == -999)) { + return [_subscriber didCloseWithError:nil]; + } + if (response.httpStatusCode == 200) { + return; + } + + NSString *errorStatus = [NSString stringWithFormat:@"URLSession HTTP error code: %ld", + (long)httpResponse.statusCode]; + NSError *wrappedError = [NSError errorWithDomain:RLMAppErrorDomain + code:RLMAppErrorHttpRequestFailed + userInfo:@{NSLocalizedDescriptionKey: errorStatus, + RLMHTTPStatusCodeKey: @(httpResponse.statusCode), + NSURLErrorFailingURLErrorKey: task.currentRequest.URL, + NSUnderlyingErrorKey: error}]; + return [_subscriber didCloseWithError:wrappedError]; +} + +@end diff --git a/Pods/Realm/Realm/RLMObject.mm b/Pods/Realm/Realm/RLMObject.mm new file mode 100644 index 0000000..aedbaab --- /dev/null +++ b/Pods/Realm/Realm/RLMObject.mm @@ -0,0 +1,254 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMObject_Private.hpp" + +#import "RLMAccessor.h" +#import "RLMArray.h" +#import "RLMCollection_Private.hpp" +#import "RLMObjectBase_Private.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" + +#import + +// We declare things in RLMObject which are actually implemented in RLMObjectBase +// for documentation's sake, which leads to -Wunimplemented-method warnings. +// Other alternatives to this would be to disable -Wunimplemented-method for this +// file (but then we could miss legitimately missing things), or declaring the +// inherited things in a category (but they currently aren't nicely grouped for +// that). +@implementation RLMObject + +// synthesized in RLMObjectBase +@dynamic invalidated, realm, objectSchema; + +#pragma mark - Designated Initializers + +- (instancetype)init { + return [super init]; +} + +#pragma mark - Convenience Initializers + +- (instancetype)initWithValue:(id)value { + if (!(self = [self init])) { + return nil; + } + RLMInitializeWithValue(self, value, RLMSchema.partialPrivateSharedSchema); + return self; +} + +#pragma mark - Class-based Object Creation + ++ (instancetype)createInDefaultRealmWithValue:(id)value { + return (RLMObject *)RLMCreateObjectInRealmWithValue([RLMRealm defaultRealm], [self className], value, RLMUpdatePolicyError); +} + ++ (instancetype)createInRealm:(RLMRealm *)realm withValue:(id)value { + return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyError); +} + ++ (instancetype)createOrUpdateInDefaultRealmWithValue:(id)value { + return [self createOrUpdateInRealm:[RLMRealm defaultRealm] withValue:value]; +} + ++ (instancetype)createOrUpdateModifiedInDefaultRealmWithValue:(id)value { + return [self createOrUpdateModifiedInRealm:[RLMRealm defaultRealm] withValue:value]; +} + ++ (instancetype)createOrUpdateInRealm:(RLMRealm *)realm withValue:(id)value { + RLMVerifyHasPrimaryKey(self); + return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyUpdateAll); +} + ++ (instancetype)createOrUpdateModifiedInRealm:(RLMRealm *)realm withValue:(id)value { + RLMVerifyHasPrimaryKey(self); + return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyUpdateChanged); +} + +#pragma mark - Subscripting + +- (id)objectForKeyedSubscript:(NSString *)key { + return RLMObjectBaseObjectForKeyedSubscript(self, key); +} + +- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key { + RLMObjectBaseSetObjectForKeyedSubscript(self, key, obj); +} + +#pragma mark - Getting & Querying + ++ (RLMResults *)allObjects { + return RLMGetObjects(RLMRealm.defaultRealm, self.className, nil); +} + ++ (RLMResults *)allObjectsInRealm:(__unsafe_unretained RLMRealm *const)realm { + return RLMGetObjects(realm, self.className, nil); +} + ++ (RLMResults *)objectsWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsWhere:predicateFormat args:args]; + va_end(args); + return results; +} + ++ (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args { + return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + ++ (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsInRealm:realm where:predicateFormat args:args]; + va_end(args); + return results; +} + ++ (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat args:(va_list)args { + return [self objectsInRealm:realm withPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + ++ (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + return RLMGetObjects(RLMRealm.defaultRealm, self.className, predicate); +} + ++ (RLMResults *)objectsInRealm:(RLMRealm *)realm withPredicate:(NSPredicate *)predicate { + return RLMGetObjects(realm, self.className, predicate); +} + ++ (instancetype)objectForPrimaryKey:(id)primaryKey { + return RLMGetObject(RLMRealm.defaultRealm, self.className, primaryKey); +} + ++ (instancetype)objectInRealm:(RLMRealm *)realm forPrimaryKey:(id)primaryKey { + return RLMGetObject(realm, self.className, primaryKey); +} + +#pragma mark - Other Instance Methods + +- (BOOL)isEqualToObject:(RLMObject *)object { + return [object isKindOfClass:RLMObject.class] && RLMObjectBaseAreEqual(self, object); +} + +- (instancetype)freeze { + return RLMObjectFreeze(self); +} + +- (instancetype)thaw { + return RLMObjectThaw(self); +} + +- (BOOL)isFrozen { + return _realm.isFrozen; +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block { + return RLMObjectAddNotificationBlock(self, block, nil, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block + queue:(nonnull dispatch_queue_t)queue { + return RLMObjectAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block + keyPaths:(NSArray *)keyPaths { + return RLMObjectAddNotificationBlock(self, block, keyPaths, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMObjectAddNotificationBlock(self, block, keyPaths, queue); + +} + ++ (NSString *)className { + return [super className]; +} + +#pragma mark - Default values for schema definition + ++ (NSArray *)indexedProperties { + return @[]; +} + ++ (NSDictionary *)linkingObjectsProperties { + return @{}; +} + ++ (NSDictionary *)defaultPropertyValues { + return nil; +} + ++ (NSString *)primaryKey { + return nil; +} + ++ (NSArray *)ignoredProperties { + return nil; +} + ++ (NSArray *)requiredProperties { + return @[]; +} + ++ (bool)_realmIgnoreClass { + return false; +} + +@end + +@implementation RLMDynamicObject + ++ (bool)_realmIgnoreClass { + return true; +} + ++ (BOOL)shouldIncludeInDefaultSchema { + return NO; +} + +- (id)valueForUndefinedKey:(NSString *)key { + return RLMDynamicGetByName(self, key); +} + +- (void)setValue:(id)value forUndefinedKey:(NSString *)key { + RLMDynamicValidatedSet(self, key, value); +} + ++ (RLMObjectSchema *)sharedSchema { + return nil; +} + +@end + +BOOL RLMIsObjectOrSubclass(Class klass) { + return RLMIsKindOfClass(klass, RLMObjectBase.class); +} + +BOOL RLMIsObjectSubclass(Class klass) { + return RLMIsKindOfClass(class_getSuperclass(class_getSuperclass(klass)), RLMObjectBase.class); +} diff --git a/Pods/Realm/Realm/RLMObjectBase.mm b/Pods/Realm/Realm/RLMObjectBase.mm new file mode 100644 index 0000000..410a317 --- /dev/null +++ b/Pods/Realm/Realm/RLMObjectBase.mm @@ -0,0 +1,858 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMObject_Private.hpp" +#import "RLMObjectBase_Private.h" + +#import "RLMAccessor.h" +#import "RLMArray_Private.hpp" +#import "RLMDecimal128.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftCollectionBase.h" +#import "RLMSwiftSupport.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +using namespace realm; + +const NSUInteger RLMDescriptionMaxDepth = 5; + + +static bool isManagedAccessorClass(Class cls) { + const char *className = class_getName(cls); + const char accessorClassPrefix[] = "RLM:Managed"; + return strncmp(className, accessorClassPrefix, sizeof(accessorClassPrefix) - 1) == 0; +} + +static void maybeInitObjectSchemaForUnmanaged(RLMObjectBase *obj) { + Class cls = obj.class; + if (isManagedAccessorClass(cls)) { + return; + } + + obj->_objectSchema = [cls sharedSchema]; + if (!obj->_objectSchema) { + return; + } + + // set default values + if (!obj->_objectSchema.isSwiftClass) { + NSDictionary *dict = RLMDefaultValuesForObjectSchema(obj->_objectSchema); + for (NSString *key in dict) { + [obj setValue:dict[key] forKey:key]; + } + } + + // set unmanaged accessor class + object_setClass(obj, obj->_objectSchema.unmanagedClass); +} + +@interface RLMObjectBase () +@end + +@implementation RLMObjectBase + +- (instancetype)init { + if ((self = [super init])) { + maybeInitObjectSchemaForUnmanaged(self); + } + return self; +} + +- (void)dealloc { + // This can't be a unique_ptr because associated objects are removed + // *after* c++ members are destroyed and dealloc is called, and we need it + // to be in a validish state when that happens + delete _observationInfo; + _observationInfo = nullptr; +} + +static id coerceToObjectType(id obj, Class cls, RLMSchema *schema) { + if ([obj isKindOfClass:cls]) { + return obj; + } + obj = RLMBridgeSwiftValue(obj) ?: obj; + id value = [[cls alloc] init]; + RLMInitializeWithValue(value, obj, schema); + return value; +} + +static id validatedObjectForProperty(__unsafe_unretained id const obj, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained RLMProperty *const prop, + __unsafe_unretained RLMSchema *const schema) { + RLMValidateValueForProperty(obj, objectSchema, prop); + if (!obj || obj == NSNull.null) { + return nil; + } + if (prop.type == RLMPropertyTypeObject) { + Class objectClass = schema[prop.objectClassName].objectClass; + id enumerable = RLMAsFastEnumeration(obj); + if (prop.dictionary) { + NSMutableDictionary *ret = [[NSMutableDictionary alloc] init]; + for (id key in enumerable) { + id val = RLMCoerceToNil(obj[key]); + if (val) { + val = coerceToObjectType(obj[key], objectClass, schema); + } + [ret setObject:val ?: NSNull.null forKey:key]; + } + return ret; + } + else if (prop.collection) { + NSMutableArray *ret = [[NSMutableArray alloc] init]; + for (id el in enumerable) { + [ret addObject:coerceToObjectType(el, objectClass, schema)]; + } + return ret; + } + return coerceToObjectType(obj, objectClass, schema); + } + else if (prop.type == RLMPropertyTypeDecimal128 && !prop.collection) { + return [[RLMDecimal128 alloc] initWithValue:obj]; + } + return obj; +} + +void RLMInitializeWithValue(RLMObjectBase *self, id value, RLMSchema *schema) { + if (!value || value == NSNull.null) { + @throw RLMException(@"Must provide a non-nil value."); + } + + RLMObjectSchema *objectSchema = self->_objectSchema; + if (!objectSchema) { + // Will be nil if we're called during schema init, when we don't want + // to actually populate the object anyway + return; + } + + NSArray *properties = objectSchema.properties; + if (NSArray *array = RLMDynamicCast(value)) { + if (array.count > properties.count) { + @throw RLMException(@"Invalid array input: more values (%llu) than properties (%llu).", + (unsigned long long)array.count, (unsigned long long)properties.count); + } + NSUInteger i = 0; + for (id val in array) { + RLMProperty *prop = properties[i++]; + [self setValue:validatedObjectForProperty(RLMCoerceToNil(val), objectSchema, prop, schema) + forKey:prop.name]; + } + } + else { + // assume our object is an NSDictionary or an object with kvc properties + for (RLMProperty *prop in properties) { + id obj = RLMValidatedValueForProperty(value, prop.name, objectSchema.className); + + // don't set unspecified properties + if (!obj) { + continue; + } + + [self setValue:validatedObjectForProperty(RLMCoerceToNil(obj), objectSchema, prop, schema) + forKey:prop.name]; + } + } +} + +id RLMCreateManagedAccessor(Class cls, RLMClassInfo *info) { + RLMObjectBase *obj = [[cls alloc] init]; + obj->_info = info; + obj->_realm = info->realm; + obj->_objectSchema = info->rlmObjectSchema; + return obj; +} + +- (id)valueForKey:(NSString *)key { + if (_observationInfo) { + return _observationInfo->valueForKey(key); + } + return [super valueForKey:key]; +} + +// Generic Swift properties can't be dynamic, so KVO doesn't work for them by default +- (id)valueForUndefinedKey:(NSString *)key { + RLMProperty *prop = _objectSchema[key]; + if (Class swiftAccessor = prop.swiftAccessor) { + return RLMCoerceToNil([swiftAccessor get:prop on:self]); + } + return [super valueForUndefinedKey:key]; +} + +- (void)setValue:(id)value forUndefinedKey:(NSString *)key { + value = RLMCoerceToNil(value); + RLMProperty *property = _objectSchema[key]; + if (property.collection) { + if (id enumerable = RLMAsFastEnumeration(value)) { + value = validatedObjectForProperty(value, _objectSchema, property, + RLMSchema.partialPrivateSharedSchema); + } + } + if (auto swiftAccessor = property.swiftAccessor) { + [swiftAccessor set:property on:self to:value]; + } + else { + [super setValue:value forUndefinedKey:key]; + } +} + +// overridden at runtime per-class for performance ++ (NSString *)className { + NSString *className = NSStringFromClass(self); + if ([RLMSwiftSupport isSwiftClassName:className]) { + className = [RLMSwiftSupport demangleClassName:className]; + } + return className; +} + +// overridden at runtime per-class for performance ++ (RLMObjectSchema *)sharedSchema { + return [RLMSchema sharedSchemaForClass:self.class]; +} + ++ (void)initializeLinkedObjectSchemas { + for (RLMProperty *prop in self.sharedSchema.properties) { + if (prop.type == RLMPropertyTypeObject && !RLMSchema.partialPrivateSharedSchema[prop.objectClassName]) { + [[RLMSchema classForString:prop.objectClassName] initializeLinkedObjectSchemas]; + } + } +} + ++ (nullable NSArray *)_getProperties { + return nil; +} + +- (NSString *)description { + if (self.isInvalidated) { + return @"[invalid object]"; + } + + return [self descriptionWithMaxDepth:RLMDescriptionMaxDepth]; +} + +- (NSString *)descriptionWithMaxDepth:(NSUInteger)depth { + if (depth == 0) { + return @""; + } + + NSString *baseClassName = _objectSchema.className; + NSMutableString *mString = [NSMutableString stringWithFormat:@"%@ {\n", baseClassName]; + + for (RLMProperty *property in _objectSchema.properties) { + id object = [(id)self objectForKeyedSubscript:property.name]; + NSString *sub; + if ([object respondsToSelector:@selector(descriptionWithMaxDepth:)]) { + sub = [object descriptionWithMaxDepth:depth - 1]; + } + else if (property.type == RLMPropertyTypeData) { + static NSUInteger maxPrintedDataLength = 24; + NSData *data = object; + NSUInteger length = data.length; + if (length > maxPrintedDataLength) { + data = [NSData dataWithBytes:data.bytes length:maxPrintedDataLength]; + } + NSString *dataDescription = [data description]; + sub = [NSString stringWithFormat:@"<%@ — %lu total bytes>", [dataDescription substringWithRange:NSMakeRange(1, dataDescription.length - 2)], (unsigned long)length]; + } + else { + sub = [object description]; + } + [mString appendFormat:@"\t%@ = %@;\n", property.name, [sub stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]]; + } + [mString appendString:@"}"]; + + return [NSString stringWithString:mString]; +} + +- (RLMRealm *)realm { + return _realm; +} + +- (RLMObjectSchema *)objectSchema { + return _objectSchema; +} + +- (BOOL)isInvalidated { + // if not unmanaged and our accessor has been detached, we have been deleted + return _info && !_row.is_valid(); +} + +- (BOOL)isEqual:(id)object { + if (RLMObjectBase *other = RLMDynamicCast(object)) { + if (_objectSchema.primaryKeyProperty || _realm.isFrozen) { + return RLMObjectBaseAreEqual(self, other); + } + } + return [super isEqual:object]; +} + +- (NSUInteger)hash { + if (_objectSchema.primaryKeyProperty) { + // If we have a primary key property, that's an immutable value which we + // can use as the identity of the object. + id primaryProperty = [self valueForKey:_objectSchema.primaryKeyProperty.name]; + + // modify the hash of our primary key value to avoid potential (although unlikely) collisions + return [primaryProperty hash] ^ 1; + } + else if (_realm.isFrozen) { + // The object key can never change for frozen objects, so that's usable + // for objects without primary keys + return static_cast(_row.get_key().value); + } + else { + // Non-frozen objects without primary keys don't have any immutable + // concept of identity that we can hash so we have to fall back to + // pointer equality + return [super hash]; + } +} + ++ (BOOL)shouldIncludeInDefaultSchema { + return RLMIsObjectSubclass(self); +} + ++ (NSString *)primaryKey { + return nil; +} + ++ (NSString *)_realmObjectName { + return nil; +} + ++ (NSDictionary *)_realmColumnNames { + return nil; +} + ++ (bool)_realmIgnoreClass { + return false; +} + ++ (bool)isEmbedded { + return false; +} + ++ (bool)isAsymmetric { + return false; +} + +// This enables to override the propertiesMapping in Swift, it is not to be used in Objective-C API. ++ (NSDictionary *)propertiesMapping { + return @{}; +} + +- (id)mutableArrayValueForKey:(NSString *)key { + id obj = [self valueForKey:key]; + if ([obj isKindOfClass:[RLMArray class]]) { + return obj; + } + return [super mutableArrayValueForKey:key]; +} + +- (id)mutableSetValueForKey:(NSString *)key { + id obj = [self valueForKey:key]; + if ([obj isKindOfClass:[RLMSet class]]) { + return obj; + } + return [super mutableSetValueForKey:key]; +} + +- (void)addObserver:(id)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + if (!_observationInfo) { + _observationInfo = new RLMObservationInfo(self); + } + _observationInfo->recordObserver(_row, _info, _objectSchema, keyPath); + + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath { + [super removeObserver:observer forKeyPath:keyPath]; + if (_observationInfo) + _observationInfo->removeObserver(); +} + ++ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { + RLMProperty *prop = [self.class sharedSchema][key]; + if (isManagedAccessorClass(self)) { + // Managed accessors explicitly call willChange/didChange for managed + // properties, so we don't want KVO to override the setters to do that + return !prop; + } + if (prop.swiftAccessor) { + // Properties with swift accessors don't have obj-c getters/setters and + // will explode if KVO tries to override them + return NO; + } + + return [super automaticallyNotifiesObserversForKey:key]; +} + ++ (void)observe:(RLMObjectBase *)object + keyPaths:(nullable NSArray *)keyPaths + block:(RLMObjectNotificationCallback)block + completion:(void (^)(RLMNotificationToken *))completion { +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return Object(_realm->_realm, *_info->objectSchema, _row); +} + +- (id)objectiveCMetadata { + return nil; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(__unused id)metadata + realm:(RLMRealm *)realm { + Object object = reference.resolve(realm->_realm); + if (!object.is_valid()) { + return nil; + } + NSString *objectClassName = @(object.get_object_schema().name.c_str()); + return RLMCreateObjectAccessor(realm->_info[objectClassName], object.get_obj()); +} + +@end + +RLMRealm *RLMObjectBaseRealm(__unsafe_unretained RLMObjectBase *object) { + return object ? object->_realm : nil; +} + +RLMObjectSchema *RLMObjectBaseObjectSchema(__unsafe_unretained RLMObjectBase *object) { + return object ? object->_objectSchema : nil; +} + +id RLMObjectBaseObjectForKeyedSubscript(RLMObjectBase *object, NSString *key) { + if (!object) { + return nil; + } + + if (object->_realm) { + return RLMDynamicGetByName(object, key); + } + else { + return [object valueForKey:key]; + } +} + +void RLMObjectBaseSetObjectForKeyedSubscript(RLMObjectBase *object, NSString *key, id obj) { + if (!object) { + return; + } + + if (object->_realm || object.class == object->_objectSchema.accessorClass) { + RLMDynamicValidatedSet(object, key, obj); + } + else { + [object setValue:obj forKey:key]; + } +} + + +BOOL RLMObjectBaseAreEqual(RLMObjectBase *o1, RLMObjectBase *o2) { + // if not the correct types throw + if ((o1 && ![o1 isKindOfClass:RLMObjectBase.class]) || (o2 && ![o2 isKindOfClass:RLMObjectBase.class])) { + @throw RLMException(@"Can only compare objects of class RLMObjectBase"); + } + // if identical object (or both are nil) + if (o1 == o2) { + return YES; + } + // if one is nil + if (o1 == nil || o2 == nil) { + return NO; + } + // if not in realm or differing realms + if (o1->_realm == nil || o1->_realm != o2->_realm) { + return NO; + } + // if either are detached + if (!o1->_row.is_valid() || !o2->_row.is_valid()) { + return NO; + } + // if table and index are the same + return o1->_row.get_table() == o2->_row.get_table() + && o1->_row.get_key() == o2->_row.get_key(); +} + +static id resolveObject(RLMObjectBase *obj, RLMRealm *realm) { + RLMObjectBase *resolved = RLMCreateManagedAccessor(obj.class, &realm->_info[obj->_info->rlmObjectSchema.className]); + resolved->_row = realm->_realm->import_copy_of(obj->_row); + if (!resolved->_row.is_valid()) { + return nil; + } + RLMInitializeSwiftAccessor(resolved, false); + return resolved; +} + +id RLMObjectFreeze(RLMObjectBase *obj) { + if (!obj->_realm && !obj.isInvalidated) { + @throw RLMException(@"Unmanaged objects cannot be frozen."); + } + RLMVerifyAttached(obj); + if (obj->_realm.frozen) { + return obj; + } + obj = resolveObject(obj, obj->_realm.freeze); + if (!obj) { + @throw RLMException(@"Cannot freeze an object in the same write transaction as it was created in."); + } + return obj; +} + +id RLMObjectThaw(RLMObjectBase *obj) { + if (!obj->_realm && !obj.isInvalidated) { + @throw RLMException(@"Unmanaged objects cannot be frozen."); + } + RLMVerifyAttached(obj); + if (!obj->_realm.frozen) { + return obj; + } + return resolveObject(obj, obj->_realm.thaw); +} + +id RLMValidatedValueForProperty(id object, NSString *key, NSString *className) { + @try { + return [object valueForKey:key]; + } + @catch (NSException *e) { + if ([e.name isEqualToString:NSUndefinedKeyException]) { + @throw RLMException(@"Invalid value '%@' to initialize object of type '%@': missing key '%@'", + object, className, key); + } + @throw; + } +} + +#pragma mark - Notifications + +namespace { +struct ObjectChangeCallbackWrapper { + RLMObjectNotificationCallback block; + RLMObjectBase *object; + void (^registrationCompletion)(); + + NSArray *propertyNames = nil; + NSArray *oldValues = nil; + bool deleted = false; + + void populateProperties(realm::CollectionChangeSet const& c) { + if (propertyNames) { + return; + } + if (!c.deletions.empty()) { + deleted = true; + return; + } + if (c.columns.empty()) { + return; + } + + // FIXME: It's possible for the column key of a persisted property + // to equal the column key of a computed property. + auto properties = [NSMutableArray new]; + for (RLMProperty *property in object->_info->rlmObjectSchema.properties) { + auto columnKey = object->_info->tableColumn(property).value; + if (c.columns.count(columnKey)) { + [properties addObject:property.name]; + } + } + for (RLMProperty *property in object->_info->rlmObjectSchema.computedProperties) { + auto columnKey = object->_info->computedTableColumn(property).value; + if (c.columns.count(columnKey)) { + [properties addObject:property.name]; + } + } + if (properties.count) { + propertyNames = properties; + } + } + + NSArray *readValues(realm::CollectionChangeSet const& c) { + if (c.empty()) { + return nil; + } + populateProperties(c); + if (!propertyNames) { + return nil; + } + + auto values = [NSMutableArray arrayWithCapacity:propertyNames.count]; + for (NSString *name in propertyNames) { + id value = [object valueForKey:name]; + if (!value || [value isKindOfClass:[RLMArray class]]) { + [values addObject:NSNull.null]; + } + else { + [values addObject:value]; + } + } + return values; + } + + void before(realm::CollectionChangeSet const& c) { + @autoreleasepool { + oldValues = readValues(c); + } + } + + void after(realm::CollectionChangeSet const& c) { + @autoreleasepool { + if (registrationCompletion) { + registrationCompletion(); + registrationCompletion = nil; + } + auto newValues = readValues(c); + if (deleted) { + block(nil, nil, nil, nil, nil); + } + else if (newValues) { + block(object, propertyNames, oldValues, newValues, nil); + } + propertyNames = nil; + oldValues = nil; + } + } +}; +} // anonymous namespace + +@interface RLMPropertyChange () +@property (nonatomic, readwrite, strong) NSString *name; +@property (nonatomic, readwrite, strong, nullable) id previousValue; +@property (nonatomic, readwrite, strong, nullable) id value; +@end + +@implementation RLMPropertyChange +- (NSString *)description { + return [NSString stringWithFormat:@" %@ %@ -> %@", + (__bridge void *)self, _name, _previousValue, _value]; +} +@end + +enum class TokenState { + Initializing, + Cancelled, + Ready +}; + +RLM_DIRECT_MEMBERS +@implementation RLMObjectNotificationToken { + RLMUnfairMutex _mutex; + __unsafe_unretained RLMRealm *_realm; + realm::Object _object; + realm::NotificationToken _token; + void (^_completion)(void); + TokenState _state; +} + +- (RLMRealm *)realm { + std::lock_guard lock(_mutex); + return _realm; +} + +- (void)suppressNextNotification { + std::lock_guard lock(_mutex); + if (_object.is_valid()) { + _token.suppress_next(); + } +} + +- (bool)invalidate { + dispatch_block_t completion; + { + std::lock_guard lock(_mutex); + if (_state == TokenState::Cancelled) { + REALM_ASSERT(!_completion); + return false; + } + _realm = nil; + _token = {}; + _object = {}; + _state = TokenState::Cancelled; + std::swap(completion, _completion); + } + if (completion) { + completion(); + } + return true; +} + +- (void)addNotificationBlock:(RLMObjectNotificationCallback)block + threadSafeReference:(RLMThreadSafeReference *)tsr + config:(RLMRealmConfiguration *)config + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + std::lock_guard lock(_mutex); + if (_state != TokenState::Initializing) { + // Token was invalidated before we got this far + return; + } + + NSError *error; + _realm = [RLMRealm realmWithConfiguration:config queue:queue error:&error]; + if (!_realm) { + block(nil, nil, nil, nil, error); + return; + } + RLMObjectBase *obj = [_realm resolveThreadSafeReference:tsr]; + + _object = realm::Object(_realm->_realm, *obj->_info->objectSchema, obj->_row); + _token = _object.add_notification_callback(ObjectChangeCallbackWrapper{block, obj}, + obj->_info->keyPathArrayFromStringArray(keyPaths)); +} + +- (void)observe:(RLMObjectBase *)obj + keyPaths:(NSArray *)keyPaths + block:(RLMObjectNotificationCallback)block { + std::lock_guard lock(_mutex); + if (_state != TokenState::Initializing) { + return; + } + _object = realm::Object(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row); + _realm = obj->_realm; + + auto completion = [self] { + dispatch_block_t completion; + { + std::lock_guard lock(_mutex); + if (_state == TokenState::Initializing) { + _state = TokenState::Ready; + } + std::swap(completion, _completion); + } + if (completion) { + completion(); + } + }; + _token = _object.add_notification_callback(ObjectChangeCallbackWrapper{block, obj, completion}, + obj->_info->keyPathArrayFromStringArray(keyPaths)); +} + +- (void)registrationComplete:(void (^)())completion { + { + std::lock_guard lock(_mutex); + if (_state == TokenState::Initializing) { + _completion = completion; + return; + } + } + completion(); +} + +RLMNotificationToken *RLMObjectBaseAddNotificationBlock(RLMObjectBase *obj, + NSArray *keyPaths, + dispatch_queue_t queue, + RLMObjectNotificationCallback block) { + if (!obj->_realm) { + @throw RLMException(@"Only objects which are managed by a Realm support change notifications"); + } + + if (!queue) { + [obj->_realm verifyNotificationsAreSupported:true]; + auto token = [[RLMObjectNotificationToken alloc] init]; + [token observe:obj keyPaths:keyPaths block:block]; + return token; + } + + RLMThreadSafeReference *tsr = [RLMThreadSafeReference referenceWithThreadConfined:(id)obj]; + auto token = [[RLMObjectNotificationToken alloc] init]; + token->_realm = obj->_realm; + RLMRealmConfiguration *config = obj->_realm.configuration; + dispatch_async(queue, ^{ + @autoreleasepool { + [token addNotificationBlock:block threadSafeReference:tsr config:config keyPaths:keyPaths queue:queue]; + } + }); + return token; +} +@end + +RLMNotificationToken *RLMObjectAddNotificationBlock(RLMObjectBase *obj, RLMObjectChangeBlock block, NSArray *keyPaths, dispatch_queue_t queue) { + return RLMObjectBaseAddNotificationBlock(obj, keyPaths, queue, ^(RLMObjectBase *, NSArray *propertyNames, + NSArray *oldValues, NSArray *newValues, NSError *error) { + if (error) { + block(false, nil, error); + } + else if (!propertyNames) { + block(true, nil, nil); + } + else { + auto properties = [NSMutableArray arrayWithCapacity:propertyNames.count]; + for (NSUInteger i = 0, count = propertyNames.count; i < count; ++i) { + auto prop = [RLMPropertyChange new]; + prop.name = propertyNames[i]; + prop.previousValue = RLMCoerceToNil(oldValues[i]); + prop.value = RLMCoerceToNil(newValues[i]); + [properties addObject:prop]; + } + block(false, properties, nil); + } + }); +} + +uint64_t RLMObjectBaseGetCombineId(__unsafe_unretained RLMObjectBase *const obj) { + if (obj.invalidated) { + RLMVerifyAttached(obj); + } + if (obj->_realm) { + return obj->_row.get_key().value; + } + return reinterpret_cast((__bridge void *)obj); +} + +@implementation RealmSwiftObject ++ (BOOL)accessInstanceVariablesDirectly { + // By default KVO will try to directly read ivars if a thing with a matching + // name is observed and there's no objc property with that name. This + // crashes when it tries to read a property wrapper ivar, and is never + // useful for Swift classes. + return NO; +} +@end + +@implementation RealmSwiftEmbeddedObject ++ (BOOL)accessInstanceVariablesDirectly { + return NO; +} +@end + +@implementation RealmSwiftAsymmetricObject ++ (BOOL)accessInstanceVariablesDirectly { + return NO; +} + ++ (bool)isAsymmetric { + return YES; +} +@end diff --git a/Pods/Realm/Realm/RLMObjectId.mm b/Pods/Realm/Realm/RLMObjectId.mm new file mode 100644 index 0000000..f156b3a --- /dev/null +++ b/Pods/Realm/Realm/RLMObjectId.mm @@ -0,0 +1,134 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMObjectId_Private.hpp" + +#import "RLMError_Private.hpp" +#import "RLMUtil.hpp" + +#import + +// Swift's obj-c bridging does not support making an obj-c defined class conform +// to Decodable, so we need a Swift-defined subclass for that. This means that +// when Realm Swift is being used, we need to produce objects of that type rather +// than our obj-c defined type. objc_runtime_visible marks the type as being +// visbile only to the obj-c runtime and not the linker, which means that it'll +// be `nil` at runtime rather than being a linker error if it's not defined, and +// valid if it happens to be defined by some other library (i.e. Realm Swift). +// +// At the point where the objects are being allocated we generally don't have +// any good way of knowing whether or not it's going to end up being used by +// Swift, so we just switch to the subclass unconditionally if the subclass +// exists. This shouldn't have any impact on obj-c code other than a small +// performance hit. +[[clang::objc_runtime_visible]] +@interface RealmSwiftObjectId : RLMObjectId +@end + +@implementation RLMObjectId +- (instancetype)init { + if ((self = [super init])) { + if (auto cls = [RealmSwiftObjectId class]; cls && cls != self.class) { + object_setClass(self, cls); + } + } + return self; +} + +- (instancetype)initWithString:(NSString *)string error:(NSError **)error { + if ((self = [self init])) { + const char *str = string.UTF8String; + if (!realm::ObjectId::is_valid_str(str)) { + if (error) { + NSString *msg = [NSString stringWithFormat:@"Invalid Object ID string '%@': must be 24 hex digits", string]; + *error = [NSError errorWithDomain:RLMErrorDomain + code:RLMErrorInvalidInput + userInfo:@{NSLocalizedDescriptionKey: msg}]; + } + return nil; + } + _value = realm::ObjectId(str); + } + return self; +} + +- (instancetype)initWithTimestamp:(NSDate *)timestamp + machineIdentifier:(int)machineIdentifier + processIdentifier:(int)processIdentifier { + if ((self = [self init])) { + _value = realm::ObjectId(RLMTimestampForNSDate(timestamp), machineIdentifier, processIdentifier); + } + return self; +} + +- (instancetype)initWithValue:(realm::ObjectId)value { + if ((self = [self init])) { + _value = value; + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + // RLMObjectID is immutable so we don't have to actually copy + return self; +} + ++ (instancetype)objectId { + return [[RLMObjectId alloc] initWithValue:realm::ObjectId::gen()]; +} + +- (BOOL)isEqual:(id)object { + if (RLMObjectId *objectId = RLMDynamicCast(object)) { + return objectId->_value == _value; + } + return NO; +} + +- (BOOL)isGreaterThan:(nullable RLMObjectId *)objectId { + return _value > objectId.value; +} + +- (BOOL)isGreaterThanOrEqualTo:(nullable RLMObjectId *)objectId { + return _value >= objectId.value; +} + +- (BOOL)isLessThan:(nullable RLMObjectId *)objectId { + return _value < objectId.value; +} + +- (BOOL)isLessThanOrEqualTo:(nullable RLMObjectId *)objectId { + return _value <= objectId.value; +} + +- (NSUInteger)hash { + return _value.hash(); +} + +- (NSString *)description { + return self.stringValue; +} + +- (NSString *)stringValue { + return @(_value.to_string().c_str()); +} + +- (NSDate *)timestamp { + return RLMTimestampToNSDate(_value.get_timestamp()); +} + +@end diff --git a/Pods/Realm/Realm/RLMObjectSchema.mm b/Pods/Realm/Realm/RLMObjectSchema.mm new file mode 100644 index 0000000..774d9c2 --- /dev/null +++ b/Pods/Realm/Realm/RLMObjectSchema.mm @@ -0,0 +1,398 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMObjectSchema_Private.hpp" + +#import "RLMEmbeddedObject.h" +#import "RLMObject_Private.h" +#import "RLMProperty_Private.hpp" +#import "RLMRealm_Dynamic.h" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSwiftCollectionBase.h" +#import "RLMSwiftSupport.h" +#import "RLMUtil.hpp" + +#import +#import + +using namespace realm; + +@protocol RLMCustomEventRepresentable +@end + +// private properties +@interface RLMObjectSchema () +@property (nonatomic, readwrite) NSDictionary *allPropertiesByName; +@property (nonatomic, readwrite) NSString *className; +@end + +@implementation RLMObjectSchema { + std::string _objectStoreName; +} + +- (instancetype)initWithClassName:(NSString *)objectClassName objectClass:(Class)objectClass properties:(NSArray *)properties { + self = [super init]; + self.className = objectClassName; + self.properties = properties; + self.objectClass = objectClass; + self.accessorClass = objectClass; + self.unmanagedClass = objectClass; + return self; +} + +// return properties by name +- (RLMProperty *)objectForKeyedSubscript:(__unsafe_unretained NSString *const)key { + return _allPropertiesByName[key]; +} + +// create property map when setting property array +- (void)setProperties:(NSArray *)properties { + _properties = properties; + [self _propertiesDidChange]; +} + +- (void)setComputedProperties:(NSArray *)computedProperties { + _computedProperties = computedProperties; + [self _propertiesDidChange]; +} + +- (void)_propertiesDidChange { + _primaryKeyProperty = nil; + NSMutableDictionary *map = [NSMutableDictionary dictionaryWithCapacity:_properties.count + _computedProperties.count]; + NSUInteger index = 0; + for (RLMProperty *prop in _properties) { + prop.index = index++; + map[prop.name] = prop; + if (prop.isPrimary) { + if (_primaryKeyProperty) { + @throw RLMException(@"Properties '%@' and '%@' are both marked as the primary key of '%@'", + prop.name, _primaryKeyProperty.name, _className); + } + _primaryKeyProperty = prop; + } + } + index = 0; + for (RLMProperty *prop in _computedProperties) { + prop.index = index++; + map[prop.name] = prop; + } + _allPropertiesByName = map; + + if (RLMIsSwiftObjectClass(_accessorClass)) { + NSMutableArray *genericProperties = [NSMutableArray new]; + for (RLMProperty *prop in _properties) { + if (prop.swiftAccessor) { + [genericProperties addObject:prop]; + } + } + // Currently all computed properties are Swift generics + [genericProperties addObjectsFromArray:_computedProperties]; + + if (genericProperties.count) { + _swiftGenericProperties = genericProperties; + } + else { + _swiftGenericProperties = nil; + } + } +} + + +- (void)setPrimaryKeyProperty:(RLMProperty *)primaryKeyProperty { + _primaryKeyProperty.isPrimary = NO; + primaryKeyProperty.isPrimary = YES; + _primaryKeyProperty = primaryKeyProperty; + _primaryKeyProperty.indexed = YES; +} + ++ (instancetype)schemaForObjectClass:(Class)objectClass { + RLMObjectSchema *schema = [RLMObjectSchema new]; + + // determine classname from objectclass as className method has not yet been updated + NSString *className = NSStringFromClass(objectClass); + bool hasSwiftName = [RLMSwiftSupport isSwiftClassName:className]; + if (hasSwiftName) { + className = [RLMSwiftSupport demangleClassName:className]; + } + + bool isSwift = hasSwiftName || RLMIsSwiftObjectClass(objectClass); + + schema.className = className; + schema.objectClass = objectClass; + schema.accessorClass = objectClass; + schema.unmanagedClass = objectClass; + schema.isSwiftClass = isSwift; + schema.hasCustomEventSerialization = [objectClass conformsToProtocol:@protocol(RLMCustomEventRepresentable)]; + + bool isEmbedded = [(id)objectClass isEmbedded]; + bool isAsymmetric = [(id)objectClass isAsymmetric]; + REALM_ASSERT(!(isEmbedded && isAsymmetric)); + schema.isEmbedded = isEmbedded; + schema.isAsymmetric = isAsymmetric; + + // create array of RLMProperties, inserting properties of superclasses first + Class cls = objectClass; + Class superClass = class_getSuperclass(cls); + NSArray *allProperties = @[]; + while (superClass && superClass != RLMObjectBase.class) { + allProperties = [[RLMObjectSchema propertiesForClass:cls isSwift:isSwift] + arrayByAddingObjectsFromArray:allProperties]; + cls = superClass; + superClass = class_getSuperclass(superClass); + } + NSArray *persistedProperties = [allProperties filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(RLMProperty *property, NSDictionary *) { + return !RLMPropertyTypeIsComputed(property.type); + }]]; + schema.properties = persistedProperties; + + NSArray *computedProperties = [allProperties filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(RLMProperty *property, NSDictionary *) { + return RLMPropertyTypeIsComputed(property.type); + }]]; + schema.computedProperties = computedProperties; + + // verify that we didn't add any properties twice due to inheritance + if (allProperties.count != [NSSet setWithArray:[allProperties valueForKey:@"name"]].count) { + NSCountedSet *countedPropertyNames = [NSCountedSet setWithArray:[allProperties valueForKey:@"name"]]; + NSArray *duplicatePropertyNames = [countedPropertyNames filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *) { + return [countedPropertyNames countForObject:object] > 1; + }]].allObjects; + + if (duplicatePropertyNames.count == 1) { + @throw RLMException(@"Property '%@' is declared multiple times in the class hierarchy of '%@'", duplicatePropertyNames.firstObject, className); + } else { + @throw RLMException(@"Object '%@' has properties that are declared multiple times in its class hierarchy: '%@'", className, [duplicatePropertyNames componentsJoinedByString:@"', '"]); + } + } + + if (NSString *primaryKey = [objectClass primaryKey]) { + for (RLMProperty *prop in schema.properties) { + if ([primaryKey isEqualToString:prop.name]) { + prop.indexed = YES; + schema.primaryKeyProperty = prop; + break; + } + } + + if (!schema.primaryKeyProperty) { + @throw RLMException(@"Primary key property '%@' does not exist on object '%@'", primaryKey, className); + } + if (schema.primaryKeyProperty.type != RLMPropertyTypeInt && + schema.primaryKeyProperty.type != RLMPropertyTypeString && + schema.primaryKeyProperty.type != RLMPropertyTypeObjectId && + schema.primaryKeyProperty.type != RLMPropertyTypeUUID) { + @throw RLMException(@"Property '%@' cannot be made the primary key of '%@' because it is not a 'string', 'int', 'objectId', or 'uuid' property.", + primaryKey, className); + } + } + + for (RLMProperty *prop in schema.properties) { + if (prop.optional && prop.collection && !prop.dictionary && (prop.type == RLMPropertyTypeObject || prop.type == RLMPropertyTypeLinkingObjects)) { + // FIXME: message is awkward + @throw RLMException(@"Property '%@.%@' cannot be made optional because optional '%@' properties are not supported.", + className, prop.name, RLMTypeToString(prop.type)); + } + } + + if ([objectClass shouldIncludeInDefaultSchema] + && schema.isSwiftClass + && schema.properties.count == 0) { + @throw RLMException(@"No properties are defined for '%@'. Did you remember to mark them with '@objc' in your model?", schema.className); + } + return schema; +} + ++ (NSArray *)propertiesForClass:(Class)objectClass isSwift:(bool)isSwiftClass { + if (NSArray *props = [objectClass _getProperties]) { + return props; + } + + // For Swift subclasses of RLMObject we need an instance of the object when parsing properties + id swiftObjectInstance = isSwiftClass ? [[objectClass alloc] init] : nil; + + NSArray *ignoredProperties = [objectClass ignoredProperties]; + NSDictionary *linkingObjectsProperties = [objectClass linkingObjectsProperties]; + NSDictionary *columnNameMap = [objectClass _realmColumnNames]; + + unsigned int count; + std::unique_ptr props(class_copyPropertyList(objectClass, &count), &free); + NSMutableArray *propArray = [NSMutableArray arrayWithCapacity:count]; + NSSet *indexed = [[NSSet alloc] initWithArray:[objectClass indexedProperties]]; + for (unsigned int i = 0; i < count; i++) { + NSString *propertyName = @(property_getName(props[i])); + if ([ignoredProperties containsObject:propertyName]) { + continue; + } + + RLMProperty *prop = nil; + if (isSwiftClass) { + prop = [[RLMProperty alloc] initSwiftPropertyWithName:propertyName + indexed:[indexed containsObject:propertyName] + linkPropertyDescriptor:linkingObjectsProperties[propertyName] + property:props[i] + instance:swiftObjectInstance]; + } + else { + prop = [[RLMProperty alloc] initWithName:propertyName + indexed:[indexed containsObject:propertyName] + linkPropertyDescriptor:linkingObjectsProperties[propertyName] + property:props[i]]; + } + + if (prop) { + if (columnNameMap) { + prop.columnName = columnNameMap[prop.name]; + } + [propArray addObject:prop]; + } + } + + if (auto requiredProperties = [objectClass requiredProperties]) { + for (RLMProperty *property in propArray) { + bool required = [requiredProperties containsObject:property.name]; + if (required && property.type == RLMPropertyTypeObject && (!property.collection || property.dictionary)) { + @throw RLMException(@"Object properties cannot be made required, " + "but '+[%@ requiredProperties]' included '%@'", objectClass, property.name); + } + property.optional &= !required; + } + } + + for (RLMProperty *property in propArray) { + if (!property.optional && property.type == RLMPropertyTypeObject && !property.collection) { + @throw RLMException(@"The `%@.%@` property must be marked as being optional.", + [objectClass className], property.name); + } + if (property.type == RLMPropertyTypeAny) { + property.optional = NO; + } + } + + return propArray; +} + +- (id)copyWithZone:(NSZone *)zone { + RLMObjectSchema *schema = [[RLMObjectSchema allocWithZone:zone] init]; + schema->_objectClass = _objectClass; + schema->_className = _className; + schema->_objectClass = _objectClass; + schema->_accessorClass = _objectClass; + schema->_unmanagedClass = _unmanagedClass; + schema->_isSwiftClass = _isSwiftClass; + schema->_isEmbedded = _isEmbedded; + schema->_isAsymmetric = _isAsymmetric; + schema->_properties = [[NSArray allocWithZone:zone] initWithArray:_properties copyItems:YES]; + schema->_computedProperties = [[NSArray allocWithZone:zone] initWithArray:_computedProperties copyItems:YES]; + [schema _propertiesDidChange]; + return schema; +} + +- (BOOL)isEqualToObjectSchema:(RLMObjectSchema *)objectSchema { + if (objectSchema.properties.count != _properties.count) { + return NO; + } + + if (![_properties isEqualToArray:objectSchema.properties]) { + return NO; + } + if (![_computedProperties isEqualToArray:objectSchema.computedProperties]) { + return NO; + } + + return YES; +} + +- (NSString *)description { + NSMutableString *propertiesString = [NSMutableString string]; + for (RLMProperty *property in self.properties) { + [propertiesString appendFormat:@"\t%@\n", [property.description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]]; + } + for (RLMProperty *property in self.computedProperties) { + [propertiesString appendFormat:@"\t%@\n", [property.description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]]; + } + return [NSString stringWithFormat:@"%@ %@{\n%@}", + self.className, _isEmbedded ? @"(embedded) " : @"", propertiesString]; +} + +- (NSString *)objectName { + return [self.objectClass _realmObjectName] ?: _className; +} + +- (std::string const&)objectStoreName { + if (_objectStoreName.empty()) { + _objectStoreName = self.objectName.UTF8String; + } + return _objectStoreName; +} + +- (realm::ObjectSchema)objectStoreCopy:(RLMSchema *)schema { + using Type = ObjectSchema::ObjectType; + ObjectSchema objectSchema; + objectSchema.name = self.objectStoreName; + objectSchema.primary_key = _primaryKeyProperty ? _primaryKeyProperty.columnName.UTF8String : ""; + objectSchema.table_type = _isAsymmetric ? Type::TopLevelAsymmetric : _isEmbedded ? Type::Embedded : Type::TopLevel; + for (RLMProperty *prop in _properties) { + Property p = [prop objectStoreCopy:schema]; + p.is_primary = (prop == _primaryKeyProperty); + objectSchema.persisted_properties.push_back(std::move(p)); + } + for (RLMProperty *prop in _computedProperties) { + objectSchema.computed_properties.push_back([prop objectStoreCopy:schema]); + } + return objectSchema; +} + ++ (instancetype)objectSchemaForObjectStoreSchema:(realm::ObjectSchema const&)objectSchema { + RLMObjectSchema *schema = [RLMObjectSchema new]; + schema.className = @(objectSchema.name.c_str()); + schema.isEmbedded = objectSchema.table_type == ObjectSchema::ObjectType::Embedded; + schema.isAsymmetric = objectSchema.table_type == ObjectSchema::ObjectType::TopLevelAsymmetric; + + // create array of RLMProperties + NSMutableArray *properties = [NSMutableArray arrayWithCapacity:objectSchema.persisted_properties.size()]; + for (const Property &prop : objectSchema.persisted_properties) { + RLMProperty *property = [RLMProperty propertyForObjectStoreProperty:prop]; + property.isPrimary = (prop.name == objectSchema.primary_key); + [properties addObject:property]; + } + schema.properties = properties; + + NSMutableArray *computedProperties = [NSMutableArray arrayWithCapacity:objectSchema.computed_properties.size()]; + for (const Property &prop : objectSchema.computed_properties) { + [computedProperties addObject:[RLMProperty propertyForObjectStoreProperty:prop]]; + } + schema.computedProperties = computedProperties; + + // get primary key from realm metadata + if (objectSchema.primary_key.length()) { + NSString *primaryKeyString = [NSString stringWithUTF8String:objectSchema.primary_key.c_str()]; + schema.primaryKeyProperty = schema[primaryKeyString]; + if (!schema.primaryKeyProperty) { + @throw RLMException(@"No property matching primary key '%@'", primaryKeyString); + } + } + + // for dynamic schema use vanilla RLMDynamicObject accessor classes + schema.objectClass = RLMObject.class; + schema.accessorClass = RLMDynamicObject.class; + schema.unmanagedClass = RLMObject.class; + + return schema; +} + +@end diff --git a/Pods/Realm/Realm/RLMObjectStore.mm b/Pods/Realm/Realm/RLMObjectStore.mm new file mode 100644 index 0000000..3332b8c --- /dev/null +++ b/Pods/Realm/Realm/RLMObjectStore.mm @@ -0,0 +1,247 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMObjectStore.h" + +#import "RLMAccessor.hpp" +#import "RLMArray_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMObject_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftCollectionBase.h" +#import "RLMSwiftSupport.h" +#import "RLMUtil.hpp" +#import "RLMSwiftValueStorage.h" + +#import +#import +#import +#import + +#import + +using namespace realm; + +static inline void RLMVerifyRealmRead(__unsafe_unretained RLMRealm *const realm) { + if (!realm) { + @throw RLMException(@"Realm must not be nil"); + } + [realm verifyThread]; + if (realm->_realm->is_closed()) { + // This message may seem overly specific, but frozen Realms are currently + // the only ones which we outright close. + @throw RLMException(@"Cannot read from a frozen Realm which has been invalidated."); + } +} + +void RLMVerifyInWriteTransaction(__unsafe_unretained RLMRealm *const realm) { + RLMVerifyRealmRead(realm); + // if realm is not writable throw + if (!realm.inWriteTransaction) { + @throw RLMException(@"Can only add, remove, or create objects in a Realm in a write transaction - call beginWriteTransaction on an RLMRealm instance first."); + } +} + +void RLMInitializeSwiftAccessor(__unsafe_unretained RLMObjectBase *const object, bool promoteExisting) { + if (!object || !object->_row || !object->_objectSchema->_isSwiftClass) { + return; + } + if (![object isKindOfClass:object->_objectSchema.objectClass]) { + // It can be a different class if it's a dynamic object, and those don't + // require any init here (and would crash since they don't have the ivars) + return; + } + + if (promoteExisting) { + for (RLMProperty *prop in object->_objectSchema.swiftGenericProperties) { + [prop.swiftAccessor promote:prop on:object]; + } + } + else { + for (RLMProperty *prop in object->_objectSchema.swiftGenericProperties) { + [prop.swiftAccessor initialize:prop on:object]; + } + } +} + +void RLMVerifyHasPrimaryKey(Class cls) { + RLMObjectSchema *schema = [cls sharedSchema]; + if (!schema.primaryKeyProperty) { + NSString *reason = [NSString stringWithFormat:@"'%@' does not have a primary key and can not be updated", schema.className]; + @throw [NSException exceptionWithName:@"RLMException" reason:reason userInfo:nil]; + } +} + +static CreatePolicy updatePolicyToCreatePolicy(RLMUpdatePolicy policy) { + CreatePolicy createPolicy = {.create = true, .copy = false, .diff = false, .update = false}; + switch (policy) { + case RLMUpdatePolicyError: + break; + case RLMUpdatePolicyUpdateChanged: + createPolicy.diff = true; + [[clang::fallthrough]]; + case RLMUpdatePolicyUpdateAll: + createPolicy.update = true; + break; + } + return createPolicy; +} + +void RLMAddObjectToRealm(__unsafe_unretained RLMObjectBase *const object, + __unsafe_unretained RLMRealm *const realm, + RLMUpdatePolicy updatePolicy) { + RLMVerifyInWriteTransaction(realm); + + CreatePolicy createPolicy = updatePolicyToCreatePolicy(updatePolicy); + createPolicy.copy = false; + auto& info = realm->_info[object->_objectSchema.className]; + RLMAccessorContext c{info}; + c.createObject(object, createPolicy); +} + +RLMObjectBase *RLMCreateObjectInRealmWithValue(RLMRealm *realm, NSString *className, + id value, RLMUpdatePolicy updatePolicy) { + RLMVerifyInWriteTransaction(realm); + + CreatePolicy createPolicy = updatePolicyToCreatePolicy(updatePolicy); + createPolicy.copy = true; + + auto& info = realm->_info[className]; + RLMAccessorContext c{info}; + RLMObjectBase *object = RLMCreateManagedAccessor(info.rlmObjectSchema.accessorClass, &info); + auto [obj, reuseExisting] = c.createObject(value, createPolicy, true); + if (reuseExisting) { + return value; + } + object->_row = std::move(obj); + RLMInitializeSwiftAccessor(object, false); + return object; +} + +void RLMCreateAsymmetricObjectInRealm(RLMRealm *realm, NSString *className, id value) { + RLMVerifyInWriteTransaction(realm); + + CreatePolicy createPolicy = {.create = true, .copy = true, .diff = false, .update = false}; + + auto& info = realm->_info[className]; + RLMAccessorContext c{info}; + c.createObject(value, createPolicy); +} + +RLMObjectBase *RLMObjectFromObjLink(RLMRealm *realm, realm::ObjLink&& objLink, bool parentIsSwiftObject) { + if (auto* tableInfo = realm->_info[objLink.get_table_key()]) { + return RLMCreateObjectAccessor(*tableInfo, objLink.get_obj_key().value); + } else { + // Construct the object dynamically. + // This code path should only be hit on first access of the object. + Class cls = parentIsSwiftObject ? [RealmSwiftDynamicObject class] : [RLMDynamicObject class]; + auto& group = realm->_realm->read_group(); + auto schema = std::make_unique(group, + group.get_table_name(objLink.get_table_key()), + objLink.get_table_key()); + RLMObjectSchema *rlmObjectSchema = [RLMObjectSchema objectSchemaForObjectStoreSchema:*schema]; + rlmObjectSchema.accessorClass = cls; + rlmObjectSchema.isSwiftClass = parentIsSwiftObject; + realm->_info.appendDynamicObjectSchema(std::move(schema), rlmObjectSchema, realm); + return RLMCreateObjectAccessor(realm->_info[rlmObjectSchema.className], objLink.get_obj_key().value); + } +} + +void RLMDeleteObjectFromRealm(__unsafe_unretained RLMObjectBase *const object, + __unsafe_unretained RLMRealm *const realm) { + if (realm != object->_realm) { + @throw RLMException(@"Can only delete an object from the Realm it belongs to."); + } + + RLMVerifyInWriteTransaction(object->_realm); + + if (object->_row.is_valid()) { + RLMObservationTracker tracker(realm, true); + object->_row.remove(); + } + object->_realm = nil; +} + +void RLMDeleteAllObjectsFromRealm(RLMRealm *realm) { + RLMVerifyInWriteTransaction(realm); + + // clear table for each object schema + for (auto& info : realm->_info) { + RLMClearTable(info.second); + } +} + +RLMResults *RLMGetObjects(__unsafe_unretained RLMRealm *const realm, + NSString *objectClassName, + NSPredicate *predicate) { + RLMVerifyRealmRead(realm); + + // create view from table and predicate + RLMClassInfo& info = realm->_info[objectClassName]; + if (!info.table()) { + // read-only realms may be missing tables since we can't add any + // missing ones on init + return [RLMResults resultsWithObjectInfo:info results:{}]; + } + + if (predicate) { + realm::Query query = RLMPredicateToQuery(predicate, info.rlmObjectSchema, realm.schema, realm.group); + return [RLMResults resultsWithObjectInfo:info + results:realm::Results(realm->_realm, std::move(query))]; + } + + return [RLMResults resultsWithObjectInfo:info + results:realm::Results(realm->_realm, info.table())]; +} + +id RLMGetObject(RLMRealm *realm, NSString *objectClassName, id key) { + RLMVerifyRealmRead(realm); + + auto& info = realm->_info[objectClassName]; + if (RLMProperty *prop = info.propertyForPrimaryKey()) { + RLMValidateValueForProperty(key, info.rlmObjectSchema, prop); + } + try { + RLMAccessorContext c{info}; + auto obj = realm::Object::get_for_primary_key(c, realm->_realm, *info.objectSchema, + key ?: NSNull.null); + if (!obj.is_valid()) + return nil; + return RLMCreateObjectAccessor(info, obj.get_obj()); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +RLMObjectBase *RLMCreateObjectAccessor(RLMClassInfo& info, int64_t key) { + return RLMCreateObjectAccessor(info, info.table()->get_object(realm::ObjKey(key))); +} + +// Create accessor and register with realm +RLMObjectBase *RLMCreateObjectAccessor(RLMClassInfo& info, const realm::Obj& obj) { + RLMObjectBase *accessor = RLMCreateManagedAccessor(info.rlmObjectSchema.accessorClass, &info); + accessor->_row = obj; + RLMInitializeSwiftAccessor(accessor, false); + return accessor; +} diff --git a/Pods/Realm/Realm/RLMObservation.mm b/Pods/Realm/Realm/RLMObservation.mm new file mode 100644 index 0000000..579f2b3 --- /dev/null +++ b/Pods/Realm/Realm/RLMObservation.mm @@ -0,0 +1,554 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMObservation.hpp" + +#import "RLMAccessor.h" +#import "RLMArray_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObject_Private.hpp" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftCollectionBase.h" +#import "RLMSwiftValueStorage.h" + +#import + +using namespace realm; + +namespace { + template + struct IteratorPair { + Iterator first; + Iterator second; + }; + template + Iterator begin(IteratorPair const& p) { + return p.first; + } + template + Iterator end(IteratorPair const& p) { + return p.second; + } + + template + auto reverse(Container const& c) { + return IteratorPair{c.rbegin(), c.rend()}; + } +} + +RLMObservationInfo::RLMObservationInfo(RLMClassInfo &objectSchema, realm::ObjKey row, id object) +: object(object) +, objectSchema(&objectSchema) +{ + setRow(*objectSchema.table(), row); +} + +RLMObservationInfo::RLMObservationInfo(id object) +: object(object) +{ +} + +RLMObservationInfo::~RLMObservationInfo() { + if (prev) { + // Not the head of the linked list, so just detach from the list + REALM_ASSERT_DEBUG(prev->next == this); + prev->next = next; + if (next) { + REALM_ASSERT_DEBUG(next->prev == this); + next->prev = prev; + } + } + else if (objectSchema) { + // The head of the list, so remove self from the object schema's array + // of observation info, either replacing self with the next info or + // removing entirely if there is no next + auto end = objectSchema->observedObjects.end(); + auto it = find(objectSchema->observedObjects.begin(), end, this); + if (it != end) { + if (next) { + *it = next; + next->prev = nullptr; + } + else { + iter_swap(it, std::prev(end)); + objectSchema->observedObjects.pop_back(); + } + } + } + // Otherwise the observed object was unmanaged, so nothing to do + +#ifdef DEBUG + // ensure that incorrect cleanup fails noisily + object = (__bridge id)(void *)-1; + prev = (RLMObservationInfo *)-1; + next = (RLMObservationInfo *)-1; +#endif +} + +NSString *RLMObservationInfo::columnName(realm::ColKey col) const noexcept { + return objectSchema->propertyForTableColumn(col).name; +} + +void RLMObservationInfo::willChange(NSString *key, NSKeyValueChange kind, NSIndexSet *indexes) const { + if (indexes) { + forEach([=](__unsafe_unretained auto o) { + [o willChange:kind valuesAtIndexes:indexes forKey:key]; + }); + } + else { + forEach([=](__unsafe_unretained auto o) { + [o willChangeValueForKey:key]; + }); + } +} + +void RLMObservationInfo::didChange(NSString *key, NSKeyValueChange kind, NSIndexSet *indexes) const { + if (indexes) { + forEach([=](__unsafe_unretained auto o) { + [o didChange:kind valuesAtIndexes:indexes forKey:key]; + }); + } + else { + forEach([=](__unsafe_unretained auto o) { + [o didChangeValueForKey:key]; + }); + } +} + +void RLMObservationInfo::prepareForInvalidation() { + REALM_ASSERT_DEBUG(objectSchema); + REALM_ASSERT_DEBUG(!prev); + for (auto info = this; info; info = info->next) + info->invalidated = true; +} + +void RLMObservationInfo::setRow(realm::Table const& table, realm::ObjKey key) { + REALM_ASSERT_DEBUG(!row); + REALM_ASSERT_DEBUG(objectSchema); + row = table.get_object(key); + for (auto info : objectSchema->observedObjects) { + if (info->row && info->row.get_key() == key) { + prev = info; + next = info->next; + if (next) + next->prev = this; + info->next = this; + return; + } + } + objectSchema->observedObjects.push_back(this); +} + +void RLMObservationInfo::recordObserver(realm::Obj& objectRow, RLMClassInfo *objectInfo, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained NSString *const keyPath) { + ++observerCount; + if (row) { + return; + } + + // add ourselves to the list of observed objects if this is the first time + // an observer is being added to a managed object + if (objectRow) { + this->objectSchema = objectInfo; + setRow(*objectRow.get_table(), objectRow.get_key()); + return; + } + + // Arrays need a reference to their containing object to avoid having to + // go through the awful proxy object from mutableArrayValueForKey. + // For managed objects we do this when the object is added or created + // (and have to to support notifications from modifying an object which + // was never observed), but for Swift classes (both RealmSwift and + // RLMObject) we can't do it then because we don't know what the parent + // object is. + + NSUInteger sep = [keyPath rangeOfString:@"."].location; + NSString *key = sep == NSNotFound ? keyPath : [keyPath substringToIndex:sep]; + RLMProperty *prop = objectSchema[key]; + if (auto swiftAccessor = prop.swiftAccessor) { + [swiftAccessor observe:prop on:object]; + } + else if (prop.collection) { + [valueForKey(key) setParent:object property:prop]; + } +} + +void RLMObservationInfo::removeObserver() { + --observerCount; +} + +id RLMObservationInfo::valueForKey(NSString *key) { + if (invalidated) { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @YES; + } + return cachedObjects[key]; + } + + if (key != lastKey) { + lastKey = key; + lastProp = objectSchema ? objectSchema->rlmObjectSchema[key] : nil; + } + + static auto superValueForKey = reinterpret_cast([NSObject methodForSelector:@selector(valueForKey:)]); + if (!lastProp) { + // Not a managed property, so use NSObject's implementation of valueForKey: + return RLMCoerceToNil(superValueForKey(object, @selector(valueForKey:), key)); + } + + auto getSuper = [&] { + return row ? RLMDynamicGet(object, lastProp) : RLMCoerceToNil(superValueForKey(object, @selector(valueForKey:), key)); + }; + + // We need to return the same object each time for observing over keypaths + // to work, so we store a cache of them here. We can't just cache them on + // the object as that leads to retain cycles. + if (lastProp.collection) { + id value = cachedObjects[key]; + if (!value) { + value = getSuper(); + if (!cachedObjects) { + cachedObjects = [NSMutableDictionary new]; + } + cachedObjects[key] = value; + } + return value; + } + + if (lastProp.type == RLMPropertyTypeObject) { + auto col = row.get_table()->get_column_key(lastProp.name.UTF8String); + if (row.is_null(col)) { + [cachedObjects removeObjectForKey:key]; + return nil; + } + + RLMObjectBase *value = cachedObjects[key]; + if (value && value->_row.get_key() == row.get(col)) { + return value; + } + value = getSuper(); + if (!cachedObjects) { + cachedObjects = [NSMutableDictionary new]; + } + cachedObjects[key] = value; + return value; + } + + return getSuper(); +} + +RLMObservationInfo *RLMGetObservationInfo(RLMObservationInfo *info, realm::ObjKey row, + RLMClassInfo& objectSchema) { + if (info) { + return info; + } + + for (RLMObservationInfo *info : objectSchema.observedObjects) { + if (info->isForRow(row)) { + return info; + } + } + + return nullptr; +} + +void RLMClearTable(RLMClassInfo &objectSchema) { + if (!objectSchema.table()) { + // Orphaned embedded object types are included in the schema but do not + // create a table at all, so we may not have a table here and just + // don't need to do anything + return; + } + + for (auto info : objectSchema.observedObjects) { + info->willChange(RLMInvalidatedKey); + } + + { + RLMObservationTracker tracker(objectSchema.realm, true); + Results(objectSchema.realm->_realm, objectSchema.table()).clear(); + + for (auto info : objectSchema.observedObjects) { + info->prepareForInvalidation(); + } + } + + for (auto info : reverse(objectSchema.observedObjects)) { + info->didChange(RLMInvalidatedKey); + } + + objectSchema.observedObjects.clear(); +} + +RLMObservationTracker::RLMObservationTracker(__unsafe_unretained RLMRealm *const realm, bool trackDeletions) +: _realm(realm) +, _group(realm.group) +{ + if (trackDeletions) { + this->trackDeletions(); + } +} + +RLMObservationTracker::~RLMObservationTracker() { + didChange(); +} + +void RLMObservationTracker::willChange(RLMObservationInfo *info, NSString *key, + NSKeyValueChange kind, NSIndexSet *indexes) { + _key = key; + _kind = kind; + _indexes = indexes; + _info = info; + if (_info) { + _info->willChange(key, kind, indexes); + } +} + +void RLMObservationTracker::trackDeletions() { + if (_group.has_cascade_notification_handler()) { + // We're nested inside another call which will handle any cascaded changes for us + return; + } + + for (auto& info : _realm->_info) { + if (!info.second.observedObjects.empty()) { + _observedTables.push_back(&info.second.observedObjects); + } + } + + // No need for change tracking if no objects are observed + if (_observedTables.empty()) { + return; + } + + _group.set_cascade_notification_handler([=](realm::Group::CascadeNotification const& cs) { + cascadeNotification(cs); + }); +} + +template +void RLMObservationTracker::cascadeNotification(CascadeNotification const& cs) { + if (cs.rows.empty() && cs.links.empty()) { + return; + } + + size_t invalidatedCount = _invalidated.size(); + size_t changeCount = _changes.size(); + + auto tableKey = [](RLMObservationInfo *info) { + return info->getRow().get_table()->get_key(); + }; + std::sort(begin(_observedTables), end(_observedTables), + [=](auto a, auto b) { return tableKey(a->front()) < tableKey(b->front()); }); + for (auto const& link : cs.links) { + auto table = std::find_if(_observedTables.begin(), _observedTables.end(), [&](auto table) { + return tableKey(table->front()) == link.origin_table; + }); + if (table == _observedTables.end()) { + continue; + } + + for (auto observer : **table) { + if (!observer->isForRow(link.origin_key)) { + continue; + } + + NSString *name = observer->columnName(link.origin_col_key); + if (observer->getRow().get_table()->get_column_type(link.origin_col_key) != type_LinkList) { + _changes.push_back({observer, name}); + continue; + } + + auto c = find_if(begin(_changes), end(_changes), [&](auto const& c) { + return c.info == observer && c.property == name; + }); + if (c == end(_changes)) { + _changes.push_back({observer, name, [NSMutableIndexSet new]}); + c = prev(end(_changes)); + } + + // We know what row index is being removed from the LinkView, + // but what we actually want is the indexes in the LinkView that + // are going away + auto linkview = observer->getRow().get_linklist(link.origin_col_key); + linkview.find_all(link.old_target_key, [&](size_t index) { + [c->indexes addIndex:index]; + }); + } + } + if (!cs.rows.empty()) { + using Row = realm::Group::CascadeNotification::row; + auto begin = cs.rows.begin(); + for (auto table : _observedTables) { + auto currentTableKey = tableKey(table->front()); + if (begin->table_key < currentTableKey) { + // Find the first deleted object in or after this table + begin = std::lower_bound(begin, cs.rows.end(), Row{currentTableKey, realm::ObjKey(0)}); + } + if (begin == cs.rows.end()) { + // No more deleted objects + break; + } + if (currentTableKey < begin->table_key) { + // Next deleted object is in a table after this one + continue; + } + + // Find the end of the deletions in this table + auto end = std::lower_bound(begin, cs.rows.end(), Row{realm::TableKey(currentTableKey.value + 1), realm::ObjKey(0)}); + + // Check each observed object to see if it's in the deleted rows + for (auto info : *table) { + if (std::binary_search(begin, end, Row{currentTableKey, info->getRow().get_key()})) { + _invalidated.push_back(info); + } + } + + // Advance the begin iterator to the start of the next table + begin = end; + if (begin == cs.rows.end()) { + break; + } + } + } + + // The relative order of these loops is very important + for (size_t i = invalidatedCount; i < _invalidated.size(); ++i) { + _invalidated[i]->willChange(RLMInvalidatedKey); + } + for (size_t i = changeCount; i < _changes.size(); ++i) { + auto const& change = _changes[i]; + change.info->willChange(change.property, NSKeyValueChangeRemoval, change.indexes); + } + for (size_t i = invalidatedCount; i < _invalidated.size(); ++i) { + _invalidated[i]->prepareForInvalidation(); + } +} + +void RLMObservationTracker::didChange() { + if (_info) { + _info->didChange(_key, _kind, _indexes); + _info = nullptr; + } + if (_observedTables.empty()) { + return; + } + _group.set_cascade_notification_handler(nullptr); + + for (auto const& change : reverse(_changes)) { + change.info->didChange(change.property, NSKeyValueChangeRemoval, change.indexes); + } + for (auto info : reverse(_invalidated)) { + info->didChange(RLMInvalidatedKey); + } + _observedTables.clear(); + _changes.clear(); + _invalidated.clear(); +} + +namespace { +template +void forEach(realm::BindingContext::ObserverState const& state, Func&& func) { + for (auto& change : state.changes) { + func(realm::ColKey(change.first), change.second, static_cast(state.info)); + } +} +} + +std::vector RLMGetObservedRows(RLMSchemaInfo const& schema) { + std::vector observers; + for (auto& table : schema) { + for (auto info : table.second.observedObjects) { + auto const& row = info->getRow(); + if (!row.is_valid()) + continue; + observers.push_back({ + row.get_table()->get_key(), + row.get_key(), + info}); + } + } + sort(begin(observers), end(observers)); + return observers; +} + +static NSKeyValueChange convert(realm::BindingContext::ColumnInfo::Kind kind) { + switch (kind) { + case realm::BindingContext::ColumnInfo::Kind::None: + case realm::BindingContext::ColumnInfo::Kind::SetAll: + return NSKeyValueChangeSetting; + case realm::BindingContext::ColumnInfo::Kind::Set: + return NSKeyValueChangeReplacement; + case realm::BindingContext::ColumnInfo::Kind::Insert: + return NSKeyValueChangeInsertion; + case realm::BindingContext::ColumnInfo::Kind::Remove: + return NSKeyValueChangeRemoval; + } +} + +static NSIndexSet *convert(realm::IndexSet const& in, NSMutableIndexSet *out) { + if (in.empty()) { + return nil; + } + + [out removeAllIndexes]; + for (auto range : in) { + [out addIndexesInRange:{range.first, range.second - range.first}]; + } + return out; +} + +void RLMWillChange(std::vector const& observed, + std::vector const& invalidated) { + for (auto info : invalidated) { + static_cast(info)->willChange(RLMInvalidatedKey); + } + if (!observed.empty()) { + NSMutableIndexSet *indexes = [NSMutableIndexSet new]; + for (auto const& o : observed) { + forEach(o, [&](realm::ColKey colKey, auto const& change, RLMObservationInfo *info) { + info->willChange(info->columnName(colKey), + convert(change.kind), convert(change.indices, indexes)); + }); + } + } + for (auto info : invalidated) { + static_cast(info)->prepareForInvalidation(); + } +} + +void RLMDidChange(std::vector const& observed, + std::vector const& invalidated) { + if (!observed.empty()) { + // Loop in reverse order to avoid O(N^2) behavior in Foundation + NSMutableIndexSet *indexes = [NSMutableIndexSet new]; + for (auto const& o : reverse(observed)) { + forEach(o, [&](realm::ColKey col, auto const& change, RLMObservationInfo *info) { + info->didChange(info->columnName(col), convert(change.kind), convert(change.indices, indexes)); + }); + } + } + for (auto const& info : reverse(invalidated)) { + static_cast(info)->didChange(RLMInvalidatedKey); + } +} diff --git a/Pods/Realm/Realm/RLMPredicateUtil.mm b/Pods/Realm/Realm/RLMPredicateUtil.mm new file mode 100644 index 0000000..05dcf46 --- /dev/null +++ b/Pods/Realm/Realm/RLMPredicateUtil.mm @@ -0,0 +1,106 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RLMPredicateUtil.hpp" + +#include + +namespace { + +struct PredicateExpressionTransformer { + PredicateExpressionTransformer(ExpressionVisitor visitor) : m_visitor(visitor) { } + + NSExpression *visit(NSExpression *expression) const; + NSPredicate *visit(NSPredicate *predicate) const; + + ExpressionVisitor m_visitor; +}; + +NSExpression *PredicateExpressionTransformer::visit(NSExpression *expression) const { + expression = m_visitor(expression); + + switch (expression.expressionType) { + case NSFunctionExpressionType: { + NSMutableArray *arguments = [NSMutableArray array]; + for (NSExpression *argument in expression.arguments) { + [arguments addObject:visit(argument)]; + } + if (expression.operand) { + return [NSExpression expressionForFunction:visit(expression.operand) selectorName:expression.function arguments:arguments]; + } else { + return [NSExpression expressionForFunction:expression.function arguments:arguments]; + } + } + + case NSUnionSetExpressionType: + return [NSExpression expressionForUnionSet:visit(expression.leftExpression) with:visit(expression.rightExpression)]; + case NSIntersectSetExpressionType: + return [NSExpression expressionForIntersectSet:visit(expression.leftExpression) with:visit(expression.rightExpression)]; + case NSMinusSetExpressionType: + return [NSExpression expressionForMinusSet:visit(expression.leftExpression) with:visit(expression.rightExpression)]; + + case NSSubqueryExpressionType: { + NSExpression *collection = expression.collection; + // NSExpression.collection is declared as id, but appears to always hold an NSExpression for subqueries. + REALM_ASSERT([collection isKindOfClass:[NSExpression class]]); + return [NSExpression expressionForSubquery:visit(collection) usingIteratorVariable:expression.variable predicate:visit(expression.predicate)]; + } + + case NSAggregateExpressionType: { + NSMutableArray *subexpressions = [NSMutableArray array]; + for (NSExpression *subexpression in expression.collection) { + [subexpressions addObject:visit(subexpression)]; + } + return [NSExpression expressionForAggregate:subexpressions]; + } + + case NSConditionalExpressionType: +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpartial-availability" + return [NSExpression expressionForConditional:visit(expression.predicate) trueExpression:visit(expression.trueExpression) falseExpression:visit(expression.falseExpression)]; +#pragma clang diagnostic pop + + default: + // The remaining expression types do not contain nested expressions or predicates. + return expression; + } +} + +NSPredicate *PredicateExpressionTransformer::visit(NSPredicate *predicate) const { + if ([predicate isKindOfClass:[NSCompoundPredicate class]]) { + NSCompoundPredicate *compoundPredicate = (NSCompoundPredicate *)predicate; + NSMutableArray *subpredicates = [NSMutableArray array]; + for (NSPredicate *subpredicate in compoundPredicate.subpredicates) { + [subpredicates addObject:visit(subpredicate)]; + } + return [[NSCompoundPredicate alloc] initWithType:compoundPredicate.compoundPredicateType subpredicates:subpredicates]; + } + if ([predicate isKindOfClass:[NSComparisonPredicate class]]) { + NSComparisonPredicate *comparisonPredicate = (NSComparisonPredicate *)predicate; + NSExpression *leftExpression = visit(comparisonPredicate.leftExpression); + NSExpression *rightExpression = visit(comparisonPredicate.rightExpression); + return [NSComparisonPredicate predicateWithLeftExpression:leftExpression rightExpression:rightExpression modifier:comparisonPredicate.comparisonPredicateModifier type:comparisonPredicate.predicateOperatorType options:comparisonPredicate.options]; + } + return predicate; +} + +} // anonymous namespace + +NSPredicate *transformPredicate(NSPredicate *predicate, ExpressionVisitor visitor) { + PredicateExpressionTransformer transformer(visitor); + return transformer.visit(predicate); +} diff --git a/Pods/Realm/Realm/RLMProperty.mm b/Pods/Realm/Realm/RLMProperty.mm new file mode 100644 index 0000000..9f45801 --- /dev/null +++ b/Pods/Realm/Realm/RLMProperty.mm @@ -0,0 +1,784 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMProperty_Private.hpp" + +#import "RLMArray_Private.hpp" +#import "RLMDictionary_Private.hpp" +#import "RLMObject.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObject_Private.h" +#import "RLMSchema_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftSupport.h" +#import "RLMUtil.hpp" + +#import + +static_assert((int)RLMPropertyTypeInt == (int)realm::PropertyType::Int); +static_assert((int)RLMPropertyTypeBool == (int)realm::PropertyType::Bool); +static_assert((int)RLMPropertyTypeFloat == (int)realm::PropertyType::Float); +static_assert((int)RLMPropertyTypeDouble == (int)realm::PropertyType::Double); +static_assert((int)RLMPropertyTypeString == (int)realm::PropertyType::String); +static_assert((int)RLMPropertyTypeData == (int)realm::PropertyType::Data); +static_assert((int)RLMPropertyTypeDate == (int)realm::PropertyType::Date); +static_assert((int)RLMPropertyTypeObject == (int)realm::PropertyType::Object); +static_assert((int)RLMPropertyTypeObjectId == (int)realm::PropertyType::ObjectId); +static_assert((int)RLMPropertyTypeDecimal128 == (int)realm::PropertyType::Decimal); +static_assert((int)RLMPropertyTypeUUID == (int)realm::PropertyType::UUID); +static_assert((int)RLMPropertyTypeAny == (int)realm::PropertyType::Mixed); + +BOOL RLMPropertyTypeIsComputed(RLMPropertyType propertyType) { + return propertyType == RLMPropertyTypeLinkingObjects; +} + +// Swift obeys the ARC naming conventions for method families (except for init) +// but the end result doesn't really work (using KVC on a method returning a +// retained value results in a leak, but not returning a retained value results +// in crashes). Objective-C makes properties with naming fitting the method +// families a compile error, so we just disallow them in Swift as well. +// http://clang.llvm.org/docs/AutomaticReferenceCounting.html#arc-method-families +void RLMValidateSwiftPropertyName(NSString *name) { + // To belong to a method family, the property name must begin with the family + // name followed by a non-lowercase letter (or nothing), with an optional + // leading underscore + const char *str = name.UTF8String; + if (str[0] == '_') + ++str; + auto nameSize = strlen(str); + + // Note that "init" is deliberately not in this list because Swift does not + // infer family membership for it. + for (auto family : {"alloc", "new", "copy", "mutableCopy"}) { + auto familySize = strlen(family); + if (nameSize < familySize || !std::equal(str, str + familySize, family)) { + continue; + } + if (familySize == nameSize || !islower(str[familySize])) { + @throw RLMException(@"Property names beginning with '%s' are not " + "supported. Swift follows ARC's ownership " + "rules for methods based on their name, which " + "results in memory leaks when accessing " + "properties which return retained values via KVC.", + family); + } + return; + } +} + +static bool rawTypeShouldBeTreatedAsComputedProperty(NSString *rawType) { + return [rawType isEqualToString:@"@\"RLMLinkingObjects\""] || [rawType hasPrefix:@"@\"RLMLinkingObjects<"]; +} + +@implementation RLMProperty + ++ (instancetype)propertyForObjectStoreProperty:(const realm::Property &)prop { + auto ret = [[RLMProperty alloc] initWithName:@(prop.name.c_str()) + type:static_cast(prop.type & ~realm::PropertyType::Flags) + objectClassName:prop.object_type.length() ? @(prop.object_type.c_str()) : nil + linkOriginPropertyName:prop.link_origin_property_name.length() ? @(prop.link_origin_property_name.c_str()) : nil + indexed:prop.is_indexed + optional:isNullable(prop.type)]; + if (is_array(prop.type)) { + ret->_array = true; + } + if (is_set(prop.type)) { + ret->_set = true; + } + if (is_dictionary(prop.type)) { + // TODO: We need a way to store the dictionary + // key type in realm::Property once we support more + // key types. + ret->_dictionaryKeyType = RLMPropertyTypeString; + ret->_dictionary = true; + } + if (!prop.public_name.empty()) { + ret->_columnName = ret->_name; + ret->_name = @(prop.public_name.c_str()); + } + return ret; +} + +- (instancetype)initWithName:(NSString *)name + type:(RLMPropertyType)type + objectClassName:(NSString *)objectClassName + linkOriginPropertyName:(NSString *)linkOriginPropertyName + indexed:(BOOL)indexed + optional:(BOOL)optional { + self = [super init]; + if (self) { + _name = name; + _type = type; + _objectClassName = objectClassName; + _linkOriginPropertyName = linkOriginPropertyName; + _indexed = indexed; + _optional = optional; + [self updateAccessors]; + } + + return self; +} + +- (void)updateAccessors { + // populate getter/setter names if generic + if (!_getterName) { + _getterName = _name; + } + if (!_setterName) { + // Objective-C setters only capitalize the first letter of the property name if it falls between 'a' and 'z' + int asciiCode = [_name characterAtIndex:0]; + BOOL shouldUppercase = asciiCode >= 'a' && asciiCode <= 'z'; + NSString *firstChar = [_name substringToIndex:1]; + firstChar = shouldUppercase ? firstChar.uppercaseString : firstChar; + _setterName = [NSString stringWithFormat:@"set%@%@:", firstChar, [_name substringFromIndex:1]]; + } + + _getterSel = NSSelectorFromString(_getterName); + _setterSel = NSSelectorFromString(_setterName); +} + +static std::optional typeFromProtocolString(const char *type) { + if (strcmp(type, "RLMValue>\"") == 0) { + return RLMPropertyTypeAny; + } + if (strncmp(type, "RLM", 3)) { + return realm::none; + } + type += 3; + if (strcmp(type, "Int>\"") == 0) { + return RLMPropertyTypeInt; + } + if (strcmp(type, "Float>\"") == 0) { + return RLMPropertyTypeFloat; + } + if (strcmp(type, "Double>\"") == 0) { + return RLMPropertyTypeDouble; + } + if (strcmp(type, "Bool>\"") == 0) { + return RLMPropertyTypeBool; + } + if (strcmp(type, "String>\"") == 0) { + return RLMPropertyTypeString; + } + if (strcmp(type, "Data>\"") == 0) { + return RLMPropertyTypeData; + } + if (strcmp(type, "Date>\"") == 0) { + return RLMPropertyTypeDate; + } + if (strcmp(type, "Decimal128>\"") == 0) { + return RLMPropertyTypeDecimal128; + } + if (strcmp(type, "ObjectId>\"") == 0) { + return RLMPropertyTypeObjectId; + } + if (strcmp(type, "UUID>\"") == 0) { + return RLMPropertyTypeUUID; + } + return realm::none; +} + +// determine RLMPropertyType from objc code - returns true if valid type was found/set +- (BOOL)setTypeFromRawType:(NSString *)rawType { + const char *code = rawType.UTF8String; + switch (*code) { + case 's': // short + case 'i': // int + case 'l': // long + case 'q': // long long + _type = RLMPropertyTypeInt; + return YES; + case 'f': + _type = RLMPropertyTypeFloat; + return YES; + case 'd': + _type = RLMPropertyTypeDouble; + return YES; + case 'c': // BOOL is stored as char - since rlm has no char type this is ok + case 'B': + _type = RLMPropertyTypeBool; + return YES; + case '@': + break; + default: + return NO; + } + + _optional = true; + static const char arrayPrefix[] = "@\"RLMArray<"; + static const int arrayPrefixLen = sizeof(arrayPrefix) - 1; + + static const char setPrefix[] = "@\"RLMSet<"; + static const int setPrefixLen = sizeof(setPrefix) - 1; + + static const char dictionaryPrefix[] = "@\"RLMDictionary<"; + static const int dictionaryPrefixLen = sizeof(dictionaryPrefix) - 1; + + static const char numberPrefix[] = "@\"NSNumber<"; + static const int numberPrefixLen = sizeof(numberPrefix) - 1; + + static const char linkingObjectsPrefix[] = "@\"RLMLinkingObjects"; + static const int linkingObjectsPrefixLen = sizeof(linkingObjectsPrefix) - 1; + + _array = strncmp(code, arrayPrefix, arrayPrefixLen) == 0; + _set = strncmp(code, setPrefix, setPrefixLen) == 0; + _dictionary = strncmp(code, dictionaryPrefix, dictionaryPrefixLen) == 0; + + if (strcmp(code, "@\"NSString\"") == 0) { + _type = RLMPropertyTypeString; + } + else if (strcmp(code, "@\"NSDate\"") == 0) { + _type = RLMPropertyTypeDate; + } + else if (strcmp(code, "@\"NSData\"") == 0) { + _type = RLMPropertyTypeData; + } + else if (strcmp(code, "@\"RLMDecimal128\"") == 0) { + _type = RLMPropertyTypeDecimal128; + } + else if (strcmp(code, "@\"RLMObjectId\"") == 0) { + _type = RLMPropertyTypeObjectId; + } + else if (strcmp(code, "@\"NSUUID\"") == 0) { + _type = RLMPropertyTypeUUID; + } + else if (strcmp(code, "@\"\"") == 0) { + _type = RLMPropertyTypeAny; + // Mixed can represent a null type but can't explicitly be an optional type. + _optional = false; + } + else if (_array || _set || _dictionary) { + size_t prefixLen = 0; + NSString *collectionName; + if (_array) { + prefixLen = arrayPrefixLen; + collectionName = @"RLMArray"; + } + else if (_set) { + prefixLen = setPrefixLen; + collectionName = @"RLMSet"; + } + else if (_dictionary) { + // get the type, by working backward from RLMDictionary + size_t typeLen = 0; + size_t codeSize = strlen(code); + for (size_t i = codeSize; i > 0; i--) { + if (code[i] == '>' && i != (codeSize-2)) { // -2 means we skip the first time we see '>' + typeLen = i; + break; + } + } + prefixLen = typeLen+size_t(2); // +2 start at the type name + collectionName = @"RLMDictionary"; + + // Get the key type + if (strstr(code + dictionaryPrefixLen, "RLMString><") != NULL) { + _dictionaryKeyType = RLMPropertyTypeString; + } + } + + if (auto type = typeFromProtocolString(code + prefixLen)) { + _type = *type; + return YES; + } + + // get object class from type string - @"RLMSomeCollection" + _objectClassName = [[NSString alloc] initWithBytes:code + prefixLen + length:strlen(code + prefixLen) - 2 // drop trailing >" + encoding:NSUTF8StringEncoding]; + + if ([RLMSchema classForString:_objectClassName]) { + // Dictionaries require object types to be nullable. This is due to + // the fact that if you delete a realm object that exists in a dictionary + // the key should stay present but the value should be null. + _optional = _dictionary; + _type = RLMPropertyTypeObject; + return YES; + } + @throw RLMException(@"Property '%@' is of type '%@<%@>' which is not a supported %@ object type. " + @"%@ can only contain instances of RLMObject subclasses. " + @"See https://www.mongodb.com/docs/realm/sdk/swift/fundamentals/relationships/#to-many-relationship " + @"for more information.", _name, collectionName, _objectClassName, collectionName, collectionName); + } + else if (strncmp(code, numberPrefix, numberPrefixLen) == 0) { + auto type = typeFromProtocolString(code + numberPrefixLen); + if (type && (*type == RLMPropertyTypeInt || *type == RLMPropertyTypeFloat || *type == RLMPropertyTypeDouble || *type == RLMPropertyTypeBool)) { + _type = *type; + return YES; + } + @throw RLMException(@"Property '%@' is of type %s which is not a supported NSNumber object type. " + @"NSNumbers can only be RLMInt, RLMFloat, RLMDouble, and RLMBool at the moment. " + @"See https://www.mongodb.com/docs/realm/sdk/swift/data-types/supported-property-types/ " + @"for more information.", _name, code + 1); + } + else if (strncmp(code, linkingObjectsPrefix, linkingObjectsPrefixLen) == 0 && + (code[linkingObjectsPrefixLen] == '"' || code[linkingObjectsPrefixLen] == '<')) { + _type = RLMPropertyTypeLinkingObjects; + _optional = false; + _array = true; + + if (!_objectClassName || !_linkOriginPropertyName) { + @throw RLMException(@"Property '%@' is of type RLMLinkingObjects but +linkingObjectsProperties did not specify the class " + "or property that is the origin of the link.", _name); + } + + // If the property was declared with a protocol indicating the contained type, validate that it matches + // the class from the dictionary returned by +linkingObjectsProperties. + if (code[linkingObjectsPrefixLen] == '<') { + NSString *classNameFromProtocol = [[NSString alloc] initWithBytes:code + linkingObjectsPrefixLen + 1 + length:strlen(code + linkingObjectsPrefixLen) - 3 // drop trailing >" + encoding:NSUTF8StringEncoding]; + if (![_objectClassName isEqualToString:classNameFromProtocol]) { + @throw RLMException(@"Property '%@' was declared with type RLMLinkingObjects<%@>, but a conflicting " + "class name of '%@' was returned by +linkingObjectsProperties.", _name, + classNameFromProtocol, _objectClassName); + } + } + } + else if (strcmp(code, "@\"NSNumber\"") == 0) { + @throw RLMException(@"Property '%@' requires a protocol defining the contained type - example: NSNumber.", _name); + } + else if (strcmp(code, "@\"RLMArray\"") == 0) { + @throw RLMException(@"Property '%@' requires a protocol defining the contained type - example: RLMArray.", _name); + } + else if (strcmp(code, "@\"RLMSet\"") == 0) { + @throw RLMException(@"Property '%@' requires a protocol defining the contained type - example: RLMSet.", _name); + } + else if (strcmp(code, "@\"RLMDictionary\"") == 0) { + @throw RLMException(@"Property '%@' requires a protocol defining the contained type - example: RLMDictionary.", _name); + } + else { + NSString *className; + Class cls = nil; + if (code[1] == '\0') { + className = @"id"; + } + else { + // for objects strip the quotes and @ + className = [rawType substringWithRange:NSMakeRange(2, rawType.length-3)]; + cls = [RLMSchema classForString:className]; + } + + if (!cls) { + @throw RLMException(@"Property '%@' is declared as '%@', which is not a supported RLMObject property type. " + @"All properties must be primitives, NSString, NSDate, NSData, NSNumber, RLMArray, RLMSet, " + @"RLMDictionary, RLMLinkingObjects, RLMDecimal128, RLMObjectId, or subclasses of RLMObject. " + @"See https://www.mongodb.com/docs/realm-legacy/docs/objc/latest/api/Classes/RLMObject.html " + @"for more information.", _name, className); + } + + _type = RLMPropertyTypeObject; + _optional = true; + _objectClassName = [cls className] ?: className; + } + return YES; +} + +- (void)parseObjcProperty:(objc_property_t)property + readOnly:(bool *)readOnly + computed:(bool *)computed + rawType:(NSString **)rawType { + unsigned int count; + objc_property_attribute_t *attrs = property_copyAttributeList(property, &count); + + *computed = true; + for (size_t i = 0; i < count; ++i) { + switch (*attrs[i].name) { + case 'T': + *rawType = @(attrs[i].value); + break; + case 'R': + *readOnly = true; + break; + case 'G': + _getterName = @(attrs[i].value); + break; + case 'S': + _setterName = @(attrs[i].value); + break; + case 'V': // backing ivar name + *computed = false; + break; + + case '&': + // retain/assign + break; + case 'C': + // copy + break; + case 'D': + // dynamic + break; + case 'N': + // nonatomic + break; + case 'P': + // GC'able + break; + case 'W': + // weak + break; + default: + break; + } + } + free(attrs); +} + +- (instancetype)initSwiftPropertyWithName:(NSString *)name + indexed:(BOOL)indexed + linkPropertyDescriptor:(RLMPropertyDescriptor *)linkPropertyDescriptor + property:(objc_property_t)property + instance:(RLMObject *)obj { + self = [super init]; + if (!self) { + return nil; + } + + RLMValidateSwiftPropertyName(name); + + _name = name; + _indexed = indexed; + + if (linkPropertyDescriptor) { + _objectClassName = [linkPropertyDescriptor.objectClass className]; + _linkOriginPropertyName = linkPropertyDescriptor.propertyName; + } + + NSString *rawType; + bool readOnly = false; + bool isComputed = false; + [self parseObjcProperty:property readOnly:&readOnly computed:&isComputed rawType:&rawType]; + + // Swift sometimes doesn't explicitly set the ivar name in the metadata, so check if + // there's an ivar with the same name as the property. + if (!readOnly && isComputed && class_getInstanceVariable([obj class], name.UTF8String)) { + isComputed = false; + } + + // Check if there's a storage ivar for a lazy property in this name. We don't honor + // @lazy in managed objects, but allow it for unmanaged objects which are + // subclasses of RLMObject (but not RealmSwift.Object). It's unclear if there's a + // good reason for this difference. + if (!readOnly && isComputed) { + // Xcode 10 and earlier + NSString *backingPropertyName = [NSString stringWithFormat:@"%@.storage", name]; + isComputed = !class_getInstanceVariable([obj class], backingPropertyName.UTF8String); + } + if (!readOnly && isComputed) { + // Xcode 11 + NSString *backingPropertyName = [NSString stringWithFormat:@"$__lazy_storage_$_%@", name]; + isComputed = !class_getInstanceVariable([obj class], backingPropertyName.UTF8String); + } + + if (readOnly || isComputed) { + return nil; + } + + id propertyValue = [obj valueForKey:_name]; + + // FIXME: temporarily workaround added since Objective-C generics used in Swift show up as `@` + // * broken starting in Swift 3.0 Xcode 8 b1 + // * tested to still be broken in Swift 3.0 Xcode 8 b6 + // * if the Realm Objective-C Swift tests pass with this removed, it's been fixed + // * once it has been fixed, remove this entire conditional block (contents included) entirely + // * Bug Report: SR-2031 https://bugs.swift.org/browse/SR-2031 + if ([rawType isEqualToString:@"@"]) { + if (propertyValue) { + rawType = [NSString stringWithFormat:@"@\"%@\"", [propertyValue class]]; + } else if (linkPropertyDescriptor) { + // we're going to naively assume that the user used the correct type since we can't check it + rawType = @"@\"RLMLinkingObjects\""; + } + } + + // convert array / set / dictionary types to objc variant + if ([rawType isEqualToString:@"@\"RLMArray\""]) { + RLMArray *value = propertyValue; + _type = value.type; + _optional = value.optional; + _array = true; + _objectClassName = value.objectClassName; + if (_type == RLMPropertyTypeObject && ![RLMSchema classForString:_objectClassName]) { + @throw RLMException(@"Property '%@' is of type 'RLMArray<%@>' which is not a supported RLMArray object type. " + @"RLMArrays can only contain instances of RLMObject subclasses. " + @"See https://www.mongodb.com/docs/realm/sdk/swift/fundamentals/relationships/#to-many-relationship " + @"for more information.", _name, _objectClassName); + } + } + else if ([rawType isEqualToString:@"@\"RLMSet\""]) { + RLMSet *value = propertyValue; + _type = value.type; + _optional = value.optional; + _set = true; + _objectClassName = value.objectClassName; + if (_type == RLMPropertyTypeObject && ![RLMSchema classForString:_objectClassName]) { + @throw RLMException(@"Property '%@' is of type 'RLMSet<%@>' which is not a supported RLMSet object type. " + @"RLMSets can only contain instances of RLMObject subclasses. " + @"See https://www.mongodb.com/docs/realm/sdk/swift/fundamentals/relationships/#to-many-relationship " + @"for more information.", _name, _objectClassName); + } + } + else if ([rawType isEqualToString:@"@\"RLMDictionary\""]) { + RLMDictionary *value = propertyValue; + _type = value.type; + _dictionaryKeyType = value.keyType; + _optional = value.optional; + _dictionary = true; + _objectClassName = value.objectClassName; + if (_type == RLMPropertyTypeObject && ![RLMSchema classForString:_objectClassName]) { + @throw RLMException(@"Property '%@' is of type 'RLMDictionary' which is not a supported RLMDictionary object type. " + @"RLMDictionarys can only contain instances of RLMObject subclasses. " + @"See https://www.mongodb.com/docs/realm/sdk/swift/fundamentals/relationships/#to-many-relationship " + @"for more information.", _name, _objectClassName); + } + } + else if ([rawType isEqualToString:@"@\"NSNumber\""]) { + const char *numberType = [propertyValue objCType]; + if (!numberType) { + @throw RLMException(@"Can't persist NSNumber without default value: use a Swift-native number type or provide a default value."); + } + _optional = true; + switch (*numberType) { + case 'i': case 'l': case 'q': + _type = RLMPropertyTypeInt; + break; + case 'f': + _type = RLMPropertyTypeFloat; + break; + case 'd': + _type = RLMPropertyTypeDouble; + break; + case 'B': case 'c': + _type = RLMPropertyTypeBool; + break; + default: + @throw RLMException(@"Can't persist NSNumber of type '%s': only integers, floats, doubles, and bools are currently supported.", numberType); + } + } + else if (![self setTypeFromRawType:rawType]) { + @throw RLMException(@"Can't persist property '%@' with incompatible type. " + "Add to Object.ignoredProperties() class method to ignore.", + self.name); + } + + if ([rawType isEqualToString:@"c"]) { + // Check if it's a BOOL or Int8 by trying to set it to 2 and seeing if + // it actually sets it to 1. + [obj setValue:@2 forKey:name]; + NSNumber *value = [obj valueForKey:name]; + _type = value.intValue == 2 ? RLMPropertyTypeInt : RLMPropertyTypeBool; + } + + // update getter/setter names + [self updateAccessors]; + + return self; +} + +- (instancetype)initWithName:(NSString *)name + indexed:(BOOL)indexed + linkPropertyDescriptor:(RLMPropertyDescriptor *)linkPropertyDescriptor + property:(objc_property_t)property +{ + self = [super init]; + if (!self) { + return nil; + } + + _name = name; + _indexed = indexed; + + if (linkPropertyDescriptor) { + _objectClassName = [linkPropertyDescriptor.objectClass className]; + _linkOriginPropertyName = linkPropertyDescriptor.propertyName; + } + + NSString *rawType; + bool isReadOnly = false; + bool isComputed = false; + [self parseObjcProperty:property readOnly:&isReadOnly computed:&isComputed rawType:&rawType]; + bool shouldBeTreatedAsComputedProperty = rawTypeShouldBeTreatedAsComputedProperty(rawType); + if ((isReadOnly || isComputed) && !shouldBeTreatedAsComputedProperty) { + return nil; + } + + if (![self setTypeFromRawType:rawType]) { + @throw RLMException(@"Can't persist property '%@' with incompatible type. " + "Add to ignoredPropertyNames: method to ignore.", self.name); + } + + if (!isReadOnly && shouldBeTreatedAsComputedProperty) { + @throw RLMException(@"Property '%@' must be declared as readonly as %@ properties cannot be written to.", + self.name, RLMTypeToString(_type)); + } + + // update getter/setter names + [self updateAccessors]; + + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + RLMProperty *prop = [[RLMProperty allocWithZone:zone] init]; + prop->_name = _name; + prop->_columnName = _columnName; + prop->_type = _type; + prop->_objectClassName = _objectClassName; + prop->_array = _array; + prop->_set = _set; + prop->_dictionary = _dictionary; + prop->_dictionaryKeyType = _dictionaryKeyType; + prop->_indexed = _indexed; + prop->_getterName = _getterName; + prop->_setterName = _setterName; + prop->_getterSel = _getterSel; + prop->_setterSel = _setterSel; + prop->_isPrimary = _isPrimary; + prop->_swiftAccessor = _swiftAccessor; + prop->_swiftIvar = _swiftIvar; + prop->_optional = _optional; + prop->_linkOriginPropertyName = _linkOriginPropertyName; + return prop; +} + +- (RLMProperty *)copyWithNewName:(NSString *)name { + RLMProperty *prop = [self copy]; + prop.name = name; + return prop; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[RLMProperty class]]) { + return NO; + } + + return [self isEqualToProperty:object]; +} + +- (BOOL)isEqualToProperty:(RLMProperty *)property { + return _type == property->_type + && _indexed == property->_indexed + && _isPrimary == property->_isPrimary + && _optional == property->_optional + && [_name isEqualToString:property->_name] + && (_objectClassName == property->_objectClassName || [_objectClassName isEqualToString:property->_objectClassName]) + && (_linkOriginPropertyName == property->_linkOriginPropertyName || + [_linkOriginPropertyName isEqualToString:property->_linkOriginPropertyName]); +} + +- (BOOL)collection { + return self.set || self.array || self.dictionary; +} + +- (NSString *)description { + NSString *objectClassName = @""; + if (self.type == RLMPropertyTypeObject || self.type == RLMPropertyTypeLinkingObjects) { + objectClassName = [NSString stringWithFormat: + @"\tobjectClassName = %@;\n" + @"\tlinkOriginPropertyName = %@;\n", + self.objectClassName, self.linkOriginPropertyName]; + } + return [NSString stringWithFormat: + @"%@ {\n" + "\ttype = %@;\n" + "%@" + "\tcolumnName = %@;\n" + "\tindexed = %@;\n" + "\tisPrimary = %@;\n" + "\tarray = %@;\n" + "\tset = %@;\n" + "\tdictionary = %@;\n" + "\toptional = %@;\n" + "}", + self.name, RLMTypeToString(self.type), + objectClassName, + self.columnName, + self.indexed ? @"YES" : @"NO", + self.isPrimary ? @"YES" : @"NO", + self.array ? @"YES" : @"NO", + self.set ? @"YES" : @"NO", + self.dictionary ? @"YES" : @"NO", + self.optional ? @"YES" : @"NO"]; +} + +- (NSString *)columnName { + return _columnName ?: _name; +} + +- (realm::Property)objectStoreCopy:(RLMSchema *)schema { + realm::Property p; + p.name = self.columnName.UTF8String; + if (_columnName) { + p.public_name = _name.UTF8String; + } + if (_objectClassName) { + RLMObjectSchema *targetSchema = schema[_objectClassName]; + p.object_type = (targetSchema.objectName ?: _objectClassName).UTF8String; + if (_linkOriginPropertyName) { + p.link_origin_property_name = (targetSchema[_linkOriginPropertyName].columnName ?: _linkOriginPropertyName).UTF8String; + } + } + p.is_indexed = static_cast(_indexed); + p.type = static_cast(_type); + if (_array) { + p.type |= realm::PropertyType::Array; + } + if (_set) { + p.type |= realm::PropertyType::Set; + } + if (_dictionary) { + p.type |= realm::PropertyType::Dictionary; + } + if (_optional || p.type == realm::PropertyType::Mixed) { + p.type |= realm::PropertyType::Nullable; + } + return p; +} + +- (NSString *)typeName { + if (!self.collection) { + return RLMTypeToString(_type); + } + NSString *collectionName; + if (_swiftAccessor) { + collectionName = _array ? @"List" : + _set ? @"MutableSet" : + @"Map"; + } + else { + collectionName = _array ? @"RLMArray" : + _set ? @"RLMSet" : + @"RLMDictionary"; + } + return [NSString stringWithFormat:@"%@<%@>", collectionName, RLMTypeToString(_type)]; +} + +@end + +@implementation RLMPropertyDescriptor + ++ (instancetype)descriptorWithClass:(Class)objectClass propertyName:(NSString *)propertyName +{ + RLMPropertyDescriptor *descriptor = [[RLMPropertyDescriptor alloc] init]; + descriptor->_objectClass = objectClass; + descriptor->_propertyName = propertyName; + return descriptor; +} + +@end diff --git a/Pods/Realm/Realm/RLMProviderClient.mm b/Pods/Realm/Realm/RLMProviderClient.mm new file mode 100644 index 0000000..48417c4 --- /dev/null +++ b/Pods/Realm/Realm/RLMProviderClient.mm @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMProviderClient_Private.hpp" + +#import "RLMApp_Private.hpp" + +#import +#import + +@implementation RLMProviderClient +- (instancetype)initWithApp:(RLMApp *)app { + self = [super init]; + if (self) { + _app = app; + } + return self; +} + +realm::util::UniqueFunction)> +RLMWrapCompletion(RLMProviderClientOptionalErrorBlock completion) { + return [completion](std::optional error) { + if (error) { + return completion(makeError(*error)); + } + completion(nil); + }; +} +@end diff --git a/Pods/Realm/Realm/RLMPushClient.mm b/Pods/Realm/Realm/RLMPushClient.mm new file mode 100644 index 0000000..61061d4 --- /dev/null +++ b/Pods/Realm/Realm/RLMPushClient.mm @@ -0,0 +1,57 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMPushClient_Private.hpp" + +#import "RLMApp_Private.hpp" +#import "RLMUser_Private.hpp" + +#import + +@implementation RLMPushClient { + std::optional _pushClient; +} + +- (instancetype)initWithPushClient:(realm::app::PushClient&&)pushClient { + if (self = [super init]) { + _pushClient = std::move(pushClient); + return self; + } + return nil; +} + +- (void)registerDeviceWithToken:(NSString *)token user:(RLMUser *)user completion:(RLMOptionalErrorBlock)completion { + _pushClient->register_device(token.UTF8String, user._syncUser, ^(std::optional error) { + if (error) { + return completion(makeError(*error)); + } + completion(nil); + }); +} + + +- (void)deregisterDeviceForUser:(RLMUser *)user completion:(RLMOptionalErrorBlock)completion { + _pushClient->deregister_device(user._syncUser, ^(std::optional error) { + if (error) { + return completion(makeError(*error)); + } + completion(nil); + }); +} + +@end diff --git a/Pods/Realm/Realm/RLMQueryUtil.mm b/Pods/Realm/Realm/RLMQueryUtil.mm new file mode 100644 index 0000000..45f343c --- /dev/null +++ b/Pods/Realm/Realm/RLMQueryUtil.mm @@ -0,0 +1,1828 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMQueryUtil.hpp" + +#import "RLMAccessor.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObject_Private.hpp" +#import "RLMPredicateUtil.hpp" +#import "RLMProperty_Private.h" +#import "RLMSchema.h" +#import "RLMUtil.hpp" + +#import +#import +#import +#import +#import +#import + +using namespace realm; + +NSString * const RLMPropertiesComparisonTypeMismatchException = @"RLMPropertiesComparisonTypeMismatchException"; +NSString * const RLMUnsupportedTypesFoundInPropertyComparisonException = @"RLMUnsupportedTypesFoundInPropertyComparisonException"; + +NSString * const RLMPropertiesComparisonTypeMismatchReason = @"Property type mismatch between %@ and %@"; +NSString * const RLMUnsupportedTypesFoundInPropertyComparisonReason = @"Comparison between %@ and %@"; + +namespace { + +// small helper to create the many exceptions thrown when parsing predicates +[[gnu::cold]] [[noreturn]] +void throwException(NSString *name, NSString *format, ...) { + va_list args; + va_start(args, format); + NSString *reason = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + + @throw [NSException exceptionWithName:name reason:reason userInfo:nil]; +} + +// check a precondition and throw an exception if it is not met +// this should be used iff the condition being false indicates a bug in the caller +// of the function checking its preconditions +void RLMPrecondition(bool condition, NSString *name, NSString *format, ...) { + if (__builtin_expect(condition, 1)) { + return; + } + + va_list args; + va_start(args, format); + NSString *reason = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + + @throw [NSException exceptionWithName:name reason:reason userInfo:nil]; +} + +BOOL propertyTypeIsNumeric(RLMPropertyType propertyType) { + switch (propertyType) { + case RLMPropertyTypeInt: + case RLMPropertyTypeFloat: + case RLMPropertyTypeDouble: + case RLMPropertyTypeDecimal128: + case RLMPropertyTypeDate: + case RLMPropertyTypeAny: + return YES; + default: + return NO; + } +} + +bool propertyTypeIsLink(RLMPropertyType type) { + return type == RLMPropertyTypeObject || type == RLMPropertyTypeLinkingObjects; +} + +bool isObjectValidForProperty(id value, RLMProperty *prop) { + if (prop.collection) { + if (propertyTypeIsLink(prop.type)) { + RLMObjectBase *obj = RLMDynamicCast(value); + if (!obj) { + obj = RLMDynamicCast(RLMBridgeSwiftValue(value)); + } + if (!obj) { + return false; + } + return [RLMObjectBaseObjectSchema(obj).className isEqualToString:prop.objectClassName]; + } + return RLMValidateValue(value, prop.type, prop.optional, false, nil); + } + return RLMIsObjectValidForProperty(value, prop); +} + + +// Equal and ContainsSubstring are used by QueryBuilder::add_string_constraint as the comparator +// for performing diacritic-insensitive comparisons. + +StringData get_string(Mixed const& m) { + if (m.is_null()) + return StringData(); + if (m.get_type() == type_String) + return m.get_string(); + auto b = m.get_binary(); + return StringData(b.data(), b.size()); +} + +bool equal(CFStringCompareFlags options, StringData v1, StringData v2) +{ + if (v1.is_null() || v2.is_null()) { + return v1.is_null() == v2.is_null(); + } + + auto s1 = util::adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8*)v1.data(), v1.size(), + kCFStringEncodingUTF8, false, kCFAllocatorNull)); + auto s2 = util::adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8*)v2.data(), v2.size(), + kCFStringEncodingUTF8, false, kCFAllocatorNull)); + + return CFStringCompare(s1.get(), s2.get(), options) == kCFCompareEqualTo; +} + +template +struct Equal { + using CaseSensitive = Equal; + using CaseInsensitive = Equal; + + bool operator()(Mixed v1, Mixed v2) const + { + return equal(options, get_string(v1), get_string(v2)); + } + + static const char* description() { return options & kCFCompareCaseInsensitive ? "==[cd]" : "==[d]"; } +}; + +template +struct NotEqual { + using CaseSensitive = NotEqual; + using CaseInsensitive = NotEqual; + + bool operator()(Mixed v1, Mixed v2) const + { + return !equal(options, get_string(v1), get_string(v2)); + } + + static const char* description() { return options & kCFCompareCaseInsensitive ? "!=[cd]" : "!=[d]"; } +}; + +bool contains_substring(CFStringCompareFlags options, StringData v1, StringData v2) +{ + if (v2.is_null()) { + // Everything contains NULL + return true; + } + + if (v1.is_null()) { + // NULL contains nothing (except NULL, handled above) + return false; + } + + if (v2.size() == 0) { + // Everything (except NULL, handled above) contains the empty string + return true; + } + + auto s1 = util::adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8*)v1.data(), v1.size(), + kCFStringEncodingUTF8, false, kCFAllocatorNull)); + auto s2 = util::adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8*)v2.data(), v2.size(), + kCFStringEncodingUTF8, false, kCFAllocatorNull)); + + return CFStringFind(s1.get(), s2.get(), options).location != kCFNotFound; +} + +template +struct ContainsSubstring { + using CaseSensitive = ContainsSubstring; + using CaseInsensitive = ContainsSubstring; + + bool operator()(Mixed v1, Mixed v2) const + { + return contains_substring(options, get_string(v1), get_string(v2)); + } + + static const char* description() { return options & kCFCompareCaseInsensitive ? "CONTAINS[cd]" : "CONTAINS[d]"; } +}; + + +NSString *operatorName(NSPredicateOperatorType operatorType) +{ + switch (operatorType) { + case NSLessThanPredicateOperatorType: + return @"<"; + case NSLessThanOrEqualToPredicateOperatorType: + return @"<="; + case NSGreaterThanPredicateOperatorType: + return @">"; + case NSGreaterThanOrEqualToPredicateOperatorType: + return @">="; + case NSEqualToPredicateOperatorType: + return @"=="; + case NSNotEqualToPredicateOperatorType: + return @"!="; + case NSMatchesPredicateOperatorType: + return @"MATCHES"; + case NSLikePredicateOperatorType: + return @"LIKE"; + case NSBeginsWithPredicateOperatorType: + return @"BEGINSWITH"; + case NSEndsWithPredicateOperatorType: + return @"ENDSWITH"; + case NSInPredicateOperatorType: + return @"IN"; + case NSContainsPredicateOperatorType: + return @"CONTAINS"; + case NSBetweenPredicateOperatorType: + return @"BETWEEN"; + case NSCustomSelectorPredicateOperatorType: + return @"custom selector"; + } + + return [NSString stringWithFormat:@"unknown operator %lu", (unsigned long)operatorType]; +} + +[[gnu::cold]] [[noreturn]] +void unsupportedOperator(RLMPropertyType datatype, NSPredicateOperatorType operatorType) { + throwException(@"Invalid operator type", + @"Operator '%@' not supported for type '%@'", + operatorName(operatorType), RLMTypeToString(datatype)); +} + +bool isNSNull(id value) { + return !value || value == NSNull.null; +} + +template +bool isNSNull(T) { + return false; +} + +Table& get_table(Group& group, RLMObjectSchema *objectSchema) +{ + return *ObjectStore::table_for_object_type(group, objectSchema.objectStoreName); +} + +// A reference to a column within a query. Can be resolved to a Columns for use in query expressions. +class ColumnReference { +public: + ColumnReference(Query& query, Group& group, RLMSchema *schema, RLMProperty* property, std::vector&& links = {}) + : m_links(std::move(links)), m_property(property), m_schema(schema), m_group(&group), m_query(&query), m_link_chain(query.get_table()) + { + for (const auto& link : m_links) { + if (link.type != RLMPropertyTypeLinkingObjects) { + m_link_chain.link(link.columnName.UTF8String); + } + else { + auto [link_origin_table, link_origin_column] = link_origin(link); + m_link_chain.backlink(link_origin_table, link_origin_column); + } + } + m_col = m_link_chain.get_current_table()->get_column_key(m_property.columnName.UTF8String); + } + + ColumnReference(Query& query, Group& group, RLMSchema *schema) + : m_schema(schema), m_group(&group), m_query(&query) + { + } + + template + auto resolve(SubQuery&&... subquery) const + { + static_assert(sizeof...(SubQuery) < 2, "resolve() takes at most one subquery"); + + // LinkChain::column() mutates it, so we need to make a copy + auto lc = m_link_chain; + if (type() != RLMPropertyTypeLinkingObjects) { + return lc.column(column(), std::forward(subquery)...); + } + + if constexpr (std::is_same_v) { + auto [table, col] = link_origin(m_property); + return lc.column(table, col, std::forward(subquery)...); + } + + REALM_TERMINATE("LinkingObjects property did not have column type Link"); + } + + RLMProperty *property() const { return m_property; } + ColKey column() const { return m_col; } + RLMPropertyType type() const { return property().type; } + + RLMObjectSchema *link_target_object_schema() const + { + REALM_ASSERT(is_link()); + return m_schema[property().objectClassName]; + } + + bool is_link() const noexcept { + return propertyTypeIsLink(type()); + } + + bool has_any_to_many_links() const { + return std::any_of(begin(m_links), end(m_links), + [](RLMProperty *property) { return property.collection; }); + } + + ColumnReference last_link_column() const { + REALM_ASSERT(!m_links.empty()); + return {*m_query, *m_group, m_schema, m_links.back(), {m_links.begin(), m_links.end() - 1}}; + } + + ColumnReference column_ignoring_links(Query& query) const { + return {query, *m_group, m_schema, m_property}; + } + + ColumnReference append(RLMProperty *prop) const { + auto links = m_links; + if (m_property) { + links.push_back(m_property); + } + return ColumnReference(*m_query, *m_group, m_schema, prop, std::move(links)); + } + + void validate_comparison(id value) const { + RLMPrecondition(isObjectValidForProperty(value, m_property), + @"Invalid value", @"Cannot compare value '%@' of type '%@' to property '%@' of type '%@'", + value, [value class], m_property.name, m_property.objectClassName ?: RLMTypeToString(m_property.type)); + if (RLMObjectBase *obj = RLMDynamicCast(value)) { + RLMPrecondition(!obj->_row.is_valid() || m_group == &obj->_realm.group, + @"Invalid value origin", @"Object must be from the Realm being queried"); + } + } + +private: + std::pair link_origin(RLMProperty *prop) const + { + RLMObjectSchema *link_origin_schema = m_schema[prop.objectClassName]; + Table& link_origin_table = get_table(*m_group, link_origin_schema); + NSString *column_name = link_origin_schema[prop.linkOriginPropertyName].columnName; + auto link_origin_column = link_origin_table.get_column_key(column_name.UTF8String); + return {link_origin_table, link_origin_column}; + } + + std::vector m_links; + RLMProperty *m_property; + RLMSchema *m_schema; + Group *m_group; + Query *m_query; + LinkChain m_link_chain; + ColKey m_col; +}; + +class CollectionOperation { +public: + enum Type { + None, + Count, + Minimum, + Maximum, + Sum, + Average, + // Dictionary specific. + AllKeys + }; + + CollectionOperation(Type type, ColumnReference&& link_column, ColumnReference&& column) + : m_type(type) + , m_link_column(std::move(link_column)) + , m_column(std::move(column)) + { + REALM_ASSERT(m_type != None); + } + + Type type() const { return m_type; } + const ColumnReference& link_column() const { return m_link_column; } + const ColumnReference& column() const { return m_column; } + + void validate_comparison(id value) const { + bool valid = true; + switch (m_type) { + case Count: + RLMPrecondition([value isKindOfClass:[NSNumber class]], @"Invalid operand", + @"%@ can only be compared with a numeric value.", name_for_type(m_type)); + return; + case Average: + case Minimum: + case Maximum: + // Null on min/max/average matches arrays with no non-null values, including on non-nullable types + valid = isNSNull(value) || isObjectValidForProperty(value, m_column.property()); + break; + case Sum: + // Sums are never null + valid = !isNSNull(value) && isObjectValidForProperty(value, m_column.property()); + break; + case AllKeys: + RLMPrecondition(isNSNull(value) || [value isKindOfClass:[NSString class]], @"Invalid operand", + @"@allKeys can only be compared with a string value."); + return; + case None: break; + } + RLMPrecondition(valid, @"Invalid operand", + @"%@ on a property of type %@ cannot be compared with '%@'", + name_for_type(m_type), RLMTypeToString(m_column.type()), value); + } + + void validate_comparison(const ColumnReference& column) const { + switch (m_type) { + case Count: + RLMPrecondition(propertyTypeIsNumeric(column.type()), @"Invalid operand", + @"%@ can only be compared with a numeric value.", name_for_type(m_type)); + break; + case Average: case Minimum: case Maximum: case Sum: + RLMPrecondition(propertyTypeIsNumeric(column.type()), @"Invalid operand", + @"%@ on a property of type %@ cannot be compared with property of type '%@'", + name_for_type(m_type), RLMTypeToString(m_column.type()), RLMTypeToString(column.type())); + break; + case AllKeys: + RLMPrecondition(column.type() == RLMPropertyTypeString, @"Invalid operand", + @"@allKeys can only be compared with a string value."); + break; + case None: break; + } + } + + static Type type_for_name(NSString *name) { + if ([name isEqualToString:@"@count"]) { + return Count; + } + if ([name isEqualToString:@"@min"]) { + return Minimum; + } + if ([name isEqualToString:@"@max"]) { + return Maximum; + } + if ([name isEqualToString:@"@sum"]) { + return Sum; + } + if ([name isEqualToString:@"@avg"]) { + return Average; + } + if ([name isEqualToString:@"@allKeys"]) { + return AllKeys; + } + return None; + } + +private: + static NSString *name_for_type(Type type) { + switch (type) { + case Count: return @"@count"; + case Minimum: return @"@min"; + case Maximum: return @"@max"; + case Sum: return @"@sum"; + case Average: return @"@avg"; + case AllKeys: return @"@allKeys"; + case None: REALM_UNREACHABLE(); + } + } + + Type m_type; + ColumnReference m_link_column; + ColumnReference m_column; +}; + +struct KeyPath; + +class QueryBuilder { +public: + QueryBuilder(Query& query, Group& group, RLMSchema *schema) + : m_query(query), m_group(group), m_schema(schema) { } + + void apply_predicate(NSPredicate *predicate, RLMObjectSchema *objectSchema); + + + void apply_collection_operator_expression(KeyPath&& kp, id value, NSComparisonPredicate *pred); + void apply_value_expression(KeyPath&& kp, id value, NSComparisonPredicate *pred); + void apply_column_expression(KeyPath&& left, KeyPath&& right, NSComparisonPredicate *predicate); + void apply_function_expression(RLMObjectSchema *objectSchema, NSExpression *functionExpression, + NSPredicateOperatorType operatorType, NSExpression *right); + void apply_map_expression(RLMObjectSchema *objectSchema, NSExpression *functionExpression, + NSComparisonPredicateOptions options, NSPredicateOperatorType operatorType, + NSExpression *right); + + template + void add_numeric_constraint(RLMPropertyType datatype, + NSPredicateOperatorType operatorType, + A&& lhs, B&& rhs); + + template + void add_bool_constraint(RLMPropertyType, NSPredicateOperatorType operatorType, A&& lhs, B&& rhs); + + template + void add_mixed_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + Columns&& column, T value); + + template + void add_mixed_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + Columns&& column, const ColumnReference& c); + + template + void do_add_mixed_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + Columns&& column, Mixed&& value); + + template + void add_substring_constraint(const T& value, Query condition); + template + void add_substring_constraint(const Columns& value, Query condition); + + template + void add_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + C&& column, T&& value); + + template + void add_diacritic_sensitive_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + C&& column, T&& value); + template + void do_add_diacritic_sensitive_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + C&& column, T&& value); + + template + void add_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + ColumnReference const& column, R const& rhs); + template typename W, typename T> + void do_add_constraint(RLMPropertyType type, NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, ColumnReference const& column, T&& value); + + void add_between_constraint(const ColumnReference& column, id value); + + void add_memberwise_equality_constraint(const ColumnReference& column, RLMObjectBase *obj); + + void add_link_constraint(NSPredicateOperatorType operatorType, const ColumnReference& column, RLMObjectBase *obj); + void add_link_constraint(NSPredicateOperatorType operatorType, const ColumnReference& column, realm::null); + void add_link_constraint(NSPredicateOperatorType, const ColumnReference&, const ColumnReference&); + + template + void add_collection_operation_constraint(NSPredicateOperatorType operatorType, + const CollectionOperation& collectionOperation, R&& rhs, + NSComparisonPredicateOptions comparisionOptions); + template + void add_collection_operation_constraint(NSPredicateOperatorType operatorType, + const CollectionOperation& collectionOperation, R&& rhs, + NSComparisonPredicateOptions comparisionOptions); + template + void add_collection_operation_constraint(NSPredicateOperatorType operatorType, + const CollectionOperation& collectionOperation, R&& rhs, + NSComparisonPredicateOptions comparisionOptions); + + + CollectionOperation collection_operation_from_key_path(KeyPath&& kp); + ColumnReference column_reference_from_key_path(KeyPath&& kp, bool isAggregate); + + +private: + Query& m_query; + Group& m_group; + RLMSchema *m_schema; +}; + +#pragma mark Numeric Constraints + +// add a clause for numeric constraints based on operator type +template +void QueryBuilder::add_numeric_constraint(RLMPropertyType datatype, + NSPredicateOperatorType operatorType, + A&& lhs, B&& rhs) +{ + switch (operatorType) { + case NSLessThanPredicateOperatorType: + m_query.and_query(lhs < rhs); + break; + case NSLessThanOrEqualToPredicateOperatorType: + m_query.and_query(lhs <= rhs); + break; + case NSGreaterThanPredicateOperatorType: + m_query.and_query(lhs > rhs); + break; + case NSGreaterThanOrEqualToPredicateOperatorType: + m_query.and_query(lhs >= rhs); + break; + case NSEqualToPredicateOperatorType: + m_query.and_query(lhs == rhs); + break; + case NSNotEqualToPredicateOperatorType: + m_query.and_query(lhs != rhs); + break; + default: + unsupportedOperator(datatype, operatorType); + } +} + +template +void QueryBuilder::add_bool_constraint(RLMPropertyType datatype, + NSPredicateOperatorType operatorType, + A&& lhs, B&& rhs) { + switch (operatorType) { + case NSEqualToPredicateOperatorType: + m_query.and_query(lhs == rhs); + break; + case NSNotEqualToPredicateOperatorType: + m_query.and_query(lhs != rhs); + break; + default: + unsupportedOperator(datatype, operatorType); + } +} + +#pragma mark String Constraints + +template +void QueryBuilder::add_substring_constraint(const T& value, Query condition) { + // Foundation always returns false for substring operations with a RHS of null or "". + m_query.and_query(value.size() + ? std::move(condition) + : std::unique_ptr(new FalseExpression)); +} + +template<> +void QueryBuilder::add_substring_constraint(const Mixed& value, Query condition) { + // Foundation always returns false for substring operations with a RHS of null or "". + m_query.and_query(value.get_string().size() + ? std::move(condition) + : std::unique_ptr(new FalseExpression)); +} + + +template +void QueryBuilder::add_substring_constraint(const Columns& value, Query condition) { + // Foundation always returns false for substring operations with a RHS of null or "". + // We don't need to concern ourselves with the possibility of value traversing a link list + // and producing multiple values per row as such expressions will have been rejected. + m_query.and_query(const_cast&>(value).size() != 0 && std::move(condition)); +} + +template +Query make_diacritic_insensitive_constraint(bool caseSensitive, std::unique_ptr left, std::unique_ptr right) { + using CompareCS = Compare; + using CompareCI = Compare; + if (caseSensitive) { + return make_expression(std::move(left), std::move(right)); + } + else { + return make_expression(std::move(left), std::move(right)); + } +}; + +Query make_diacritic_insensitive_constraint(NSPredicateOperatorType operatorType, bool caseSensitive, + std::unique_ptr left, std::unique_ptr right) { + switch (operatorType) { + case NSBeginsWithPredicateOperatorType: { + constexpr auto flags = kCFCompareDiacriticInsensitive | kCFCompareAnchored; + return make_diacritic_insensitive_constraint>(caseSensitive, std::move(left), std::move(right)); + } + case NSEndsWithPredicateOperatorType: { + constexpr auto flags = kCFCompareDiacriticInsensitive | kCFCompareAnchored | kCFCompareBackwards; + return make_diacritic_insensitive_constraint>(caseSensitive, std::move(left), std::move(right)); + } + case NSContainsPredicateOperatorType: { + constexpr auto flags = kCFCompareDiacriticInsensitive; + return make_diacritic_insensitive_constraint>(caseSensitive, std::move(left), std::move(right)); + } + default: + REALM_COMPILER_HINT_UNREACHABLE(); + } +} + +template +void QueryBuilder::do_add_diacritic_sensitive_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + C&& column, T&& value) { + bool caseSensitive = !(predicateOptions & NSCaseInsensitivePredicateOption); + switch (operatorType) { + case NSBeginsWithPredicateOperatorType: + add_substring_constraint(value, column.begins_with(value, caseSensitive)); + break; + case NSEndsWithPredicateOperatorType: + add_substring_constraint(value, column.ends_with(value, caseSensitive)); + break; + case NSContainsPredicateOperatorType: + add_substring_constraint(value, column.contains(value, caseSensitive)); + break; + case NSEqualToPredicateOperatorType: + m_query.and_query(column.equal(value, caseSensitive)); + break; + case NSNotEqualToPredicateOperatorType: + m_query.and_query(column.not_equal(value, caseSensitive)); + break; + case NSLikePredicateOperatorType: + m_query.and_query(column.like(value, caseSensitive)); + break; + default: { + if constexpr (is_any_v, Columns>, Columns>>) { + unsupportedOperator(RLMPropertyTypeString, operatorType); + } + else if constexpr (is_any_v, Columns>, Columns>>) { + unsupportedOperator(RLMPropertyTypeData, operatorType); + } + else if constexpr (is_any_v, Columns>, Columns>>) { + unsupportedOperator(RLMPropertyTypeAny, operatorType); + } + else if constexpr (is_any_v>) { + // The underlying storage type Dictionary is always Mixed. This creates an issue + // where we cannot be descriptive about the exception as we do not know + // the actual value type. + throwException(@"Invalid operand type", + @"Operator '%@' not supported for string queries on Dictionary.", + operatorName(operatorType)); + } + } + } +} + +template +void QueryBuilder::add_diacritic_sensitive_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + C&& column, T&& value) { + if constexpr (is_any_v>) { + // This nesting isnt pretty but without it the compiler will complain about `T` having no known + // conversion from Columns to Mixed. This is due to the fact that all values on a + // dictionary column are boxed in Mixed. + if constexpr (is_any_v) { + do_add_diacritic_sensitive_string_constraint(operatorType, predicateOptions, std::forward(column), value); + } + } + else { + do_add_diacritic_sensitive_string_constraint(operatorType, predicateOptions, std::forward(column), value); + } +} + +template +void QueryBuilder::add_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + C&& column, T&& value) { + if (!(predicateOptions & NSDiacriticInsensitivePredicateOption)) { + add_diacritic_sensitive_string_constraint(operatorType, predicateOptions, std::forward(column), std::move(value)); + return; + } + + auto as_subexpr = util::overload{ + [](StringData value) { return make_subexpr(value); }, + [](BinaryData value) { return make_subexpr(StringData(value.data(), value.size())); }, + [](Mixed value) { + // When Mixed is null calling `get_type` will throw an exception. + if (value.is_null()) + return make_subexpr(value.get_string()); + switch (value.get_type()) { + case DataType::Type::String: + return make_subexpr(value.get_string()); + case DataType::Type::Binary: + return make_subexpr(StringData(value.get_binary().data(), value.get_binary().size())); + default: + REALM_UNREACHABLE(); + } + }, + [](auto& c) { return c.clone(); } + }; + auto left = as_subexpr(column); + auto right = as_subexpr(value); + + bool caseSensitive = !(predicateOptions & NSCaseInsensitivePredicateOption); + constexpr auto flags = kCFCompareDiacriticInsensitive | kCFCompareAnchored; + switch (operatorType) { + case NSBeginsWithPredicateOperatorType: + case NSEndsWithPredicateOperatorType: + case NSContainsPredicateOperatorType: + add_substring_constraint(value, make_diacritic_insensitive_constraint(operatorType, caseSensitive, std::move(left), std::move(right))); + break; + case NSNotEqualToPredicateOperatorType: + m_query.and_query(make_diacritic_insensitive_constraint>(caseSensitive, std::move(left), std::move(right))); + break; + case NSEqualToPredicateOperatorType: + m_query.and_query(make_diacritic_insensitive_constraint>(caseSensitive, std::move(left), std::move(right))); + break; + case NSLikePredicateOperatorType: + throwException(@"Invalid operator type", + @"Operator 'LIKE' not supported with diacritic-insensitive modifier."); + default: + unsupportedOperator(RLMPropertyTypeString, operatorType); + } +} + +id value_from_constant_expression_or_value(id value) { + if (NSExpression *exp = RLMDynamicCast(value)) { + RLMPrecondition(exp.expressionType == NSConstantValueExpressionType, + @"Invalid value", + @"Expressions within predicate aggregates must be constant values"); + return exp.constantValue; + } + return value; +} + +void validate_and_extract_between_range(id value, RLMProperty *prop, id *from, id *to) { + NSArray *array = RLMDynamicCast(value); + RLMPrecondition(array, @"Invalid value", @"object must be of type NSArray for BETWEEN operations"); + RLMPrecondition(array.count == 2, @"Invalid value", @"NSArray object must contain exactly two objects for BETWEEN operations"); + + *from = value_from_constant_expression_or_value(array.firstObject); + *to = value_from_constant_expression_or_value(array.lastObject); + RLMPrecondition(isObjectValidForProperty(*from, prop) && isObjectValidForProperty(*to, prop), + @"Invalid value", + @"NSArray objects must be of type %@ for BETWEEN operations", RLMTypeToString(prop.type)); +} + +#pragma mark Between Constraint + +void QueryBuilder::add_between_constraint(const ColumnReference& column, id value) { + if (column.has_any_to_many_links()) { + auto link_column = column.last_link_column(); + Query subquery = get_table(m_group, link_column.link_target_object_schema()).where(); + QueryBuilder(subquery, m_group, m_schema).add_between_constraint(column.column_ignoring_links(subquery), value); + + m_query.and_query(link_column.resolve(std::move(subquery)).count() > 0); + return; + } + + id from, to; + validate_and_extract_between_range(value, column.property(), &from, &to); + + if (!propertyTypeIsNumeric(column.type())) { + return unsupportedOperator(column.type(), NSBetweenPredicateOperatorType); + } + + m_query.group(); + add_constraint(NSGreaterThanOrEqualToPredicateOperatorType, 0, column, from); + add_constraint(NSLessThanOrEqualToPredicateOperatorType, 0, column, to); + m_query.end_group(); +} + +#pragma mark Link Constraints + +void QueryBuilder::add_memberwise_equality_constraint(const ColumnReference& column, RLMObjectBase *obj) { + for (RLMProperty *property in obj->_objectSchema.properties) { + // Both of these probably are implementable, but are significantly more complicated. + RLMPrecondition(!property.collection, @"Invalid predicate", + @"Unsupported property '%@.%@' for memberwise equality query: equality on collections is not implemented.", + obj->_objectSchema.className, property.name); + RLMPrecondition(!propertyTypeIsLink(property.type), @"Invalid predicate", + @"Unsupported property '%@.%@' for memberwise equality query: object links are not implemented.", + obj->_objectSchema.className, property.name); + add_constraint(NSEqualToPredicateOperatorType, 0, column.append(property), RLMDynamicGet(obj, property)); + } +} + +void QueryBuilder::add_link_constraint(NSPredicateOperatorType operatorType, + const ColumnReference& column, RLMObjectBase *obj) { + // If the value isn't actually a RLMObject then it's something which bridges + // to RLMObject, i.e. a custom type mapping to an embedded object. For those + // we want to perform memberwise equality rather than equality on the link itself. + if (![obj isKindOfClass:[RLMObjectBase class]]) { + obj = RLMBridgeSwiftValue(obj); + REALM_ASSERT([obj isKindOfClass:[RLMObjectBase class]]); + + // Collections need to use subqueries, but unary links can just use a + // group. Unary links could also use a subquery but that has worse performance. + if (column.property().collection) { + Query subquery = get_table(m_group, column.link_target_object_schema()).where(); + QueryBuilder(subquery, m_group, m_schema) + .add_memberwise_equality_constraint(ColumnReference(subquery, m_group, m_schema), obj); + if (operatorType == NSEqualToPredicateOperatorType) { + m_query.and_query(column.resolve(std::move(subquery)).count() > 0); + } + else { + // This strange condition is because "ANY list != x" isn't + // "NONE list == x"; there must be an object in the list for + // this to match + m_query.and_query(column.resolve().count() > 0 && + column.resolve(std::move(subquery)).count() == 0); + } + } + else { + if (operatorType == NSNotEqualToPredicateOperatorType) { + m_query.Not(); + } + + m_query.group(); + add_memberwise_equality_constraint(column, obj); + m_query.end_group(); + } + return; + } + + if (!obj->_row.is_valid()) { + // Unmanaged or deleted objects are not equal to any managed objects. + // For arrays this effectively checks if there are any objects in the + // array, while for links it's just always constant true or false + // (for != and = respectively). + if (column.has_any_to_many_links() || column.property().collection) { + add_link_constraint(operatorType, column, null()); + } + else if (operatorType == NSEqualToPredicateOperatorType) { + m_query.and_query(std::unique_ptr(new FalseExpression)); + } + else { + m_query.and_query(std::unique_ptr(new TrueExpression)); + } + } + else { + if (column.property().dictionary) { + add_bool_constraint(RLMPropertyTypeObject, operatorType, column.resolve(), obj->_row); + } + else { + add_bool_constraint(RLMPropertyTypeObject, operatorType, column.resolve(), obj->_row); + } + } +} + +void QueryBuilder::add_link_constraint(NSPredicateOperatorType operatorType, + const ColumnReference& column, realm::null) { + if (column.property().dictionary) { + add_bool_constraint(RLMPropertyTypeObject, operatorType, column.resolve(), null()); + } + else { + add_bool_constraint(RLMPropertyTypeObject, operatorType, column.resolve(), null()); + } +} + +void QueryBuilder::add_link_constraint(NSPredicateOperatorType operatorType, + const ColumnReference& a, const ColumnReference& b) { + if (a.property().dictionary) { + add_bool_constraint(RLMPropertyTypeObject, operatorType, a.resolve(), b.resolve()); + } + else { + add_bool_constraint(RLMPropertyTypeObject, operatorType, a.resolve(), b.resolve()); + } +} + +// iterate over an array of subpredicates, using @func to build a query from each +// one and ORing them together +template +void process_or_group(Query &query, id array, Func&& func) { + array = RLMAsFastEnumeration(array); + RLMPrecondition(array, @"Invalid value", @"IN clause requires an array of items"); + + query.group(); + + bool first = true; + for (id item in array) { + if (!first) { + query.Or(); + } + first = false; + + func(item); + } + + if (first) { + // Queries can't be empty, so if there's zero things in the OR group + // validation will fail. Work around this by adding an expression which + // will never find any rows in a table. + query.and_query(std::unique_ptr(new FalseExpression)); + } + + query.end_group(); +} + +#pragma mark Conversion Helpers + +template +realm::null value_of_type(realm::null) { + return realm::null(); +} + +template +auto value_of_type(__unsafe_unretained const id value) { + return RLMStatelessAccessorContext::unbox(value); +} + +template <> +auto value_of_type(id value) { + return RLMObjcToMixed(value, nil, CreatePolicy::Skip); +} + +template +auto value_of_type(const ColumnReference& column) { + return column.resolve(); +} + +template +void convert_null(T&& value, Fn&& fn) { + if (isNSNull(value)) { + fn(null()); + } + else { + fn(value); + } +} + +template typename W, typename T> +void QueryBuilder::do_add_constraint(RLMPropertyType type, NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, ColumnReference const& column, T&& value) +{ + switch (type) { + case RLMPropertyTypeBool: + convert_null(value, [&](auto&& value) { + add_bool_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeObjectId: + convert_null(value, [&](auto&& value) { + add_bool_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeDate: + convert_null(value, [&](auto&& value) { + add_numeric_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeDouble: + convert_null(value, [&](auto&& value) { + add_numeric_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeFloat: + convert_null(value, [&](auto&& value) { + add_numeric_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeInt: + convert_null(value, [&](auto&& value) { + add_numeric_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeDecimal128: + convert_null(value, [&](auto&& value) { + add_numeric_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeString: + add_string_constraint(operatorType, predicateOptions, column.resolve>(), + value_of_type(value)); + break; + case RLMPropertyTypeData: + add_string_constraint(operatorType, predicateOptions, + column.resolve>(), + value_of_type(value)); + break; + case RLMPropertyTypeObject: + case RLMPropertyTypeLinkingObjects: + convert_null(value, [&](auto&& value) { + add_link_constraint(operatorType, column, value); + }); + break; + case RLMPropertyTypeUUID: + convert_null(value, [&](auto&& value) { + add_bool_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeAny: + convert_null(value, [&](auto&& value) { + add_mixed_constraint(operatorType, + predicateOptions, + column.resolve>(), + value); + }); + } +} + +#pragma mark Mixed Constraints + +template +void QueryBuilder::add_mixed_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + Columns&& column, + T value) +{ + // Handle cases where a string might be '1' or '0'. Without this the string + // will be boxed as a bool and thus string query operations will crash in core. + if constexpr(std::is_same_v) { + if (auto str = RLMDynamicCast(value)) { + add_string_constraint(operatorType, predicateOptions, + std::move(column), realm::Mixed([str UTF8String])); + return; + } + } + do_add_mixed_constraint(operatorType, predicateOptions, + std::move(column), value_of_type(value)); +} + +template +void QueryBuilder::do_add_mixed_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + Columns&& column, + Mixed&& value) +{ + switch (operatorType) { + case NSLessThanPredicateOperatorType: + m_query.and_query(column < value); + break; + case NSLessThanOrEqualToPredicateOperatorType: + m_query.and_query(column <= value); + break; + case NSGreaterThanPredicateOperatorType: + m_query.and_query(column > value); + break; + case NSGreaterThanOrEqualToPredicateOperatorType: + m_query.and_query(column >= value); + break; + case NSEqualToPredicateOperatorType: + m_query.and_query(column == value); + break; + case NSNotEqualToPredicateOperatorType: + m_query.and_query(column != value); + break; + // String comparison operators: There isn't a way for a string value + // to get down here, but a rhs of NULL can + case NSLikePredicateOperatorType: + case NSMatchesPredicateOperatorType: + case NSBeginsWithPredicateOperatorType: + case NSEndsWithPredicateOperatorType: + case NSContainsPredicateOperatorType: + add_string_constraint(operatorType, predicateOptions, + std::move(column), value); + break; + default: + break; + } +} + +template +void QueryBuilder::add_mixed_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions, + Columns&& column, + const ColumnReference& value) +{ + add_bool_constraint(RLMPropertyTypeObject, operatorType, column, value.resolve()); +} + +template +using Identity = T; +template +using AlwaysDictionary = Dictionary; + +template +void QueryBuilder::add_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, ColumnReference const& column, R const& rhs) +{ + auto type = column.type(); + if (column.property().array) { + do_add_constraint(type, operatorType, predicateOptions, column, rhs); + } + else if (column.property().set) { + do_add_constraint(type, operatorType, predicateOptions, column, rhs); + } + else if (column.property().dictionary) { + do_add_constraint(type, operatorType, predicateOptions, column, rhs); + } + else { + do_add_constraint(type, operatorType, predicateOptions, column, rhs); + } +} + +struct KeyPath { + std::vector links; + RLMProperty *property; + CollectionOperation::Type collectionOperation; + bool containsToManyRelationship; +}; + +KeyPath key_path_from_string(RLMSchema *schema, RLMObjectSchema *objectSchema, NSString *keyPath) +{ + RLMProperty *property; + std::vector links; + + CollectionOperation::Type collectionOperation = CollectionOperation::None; + NSString *collectionOperationName; + bool keyPathContainsToManyRelationship = false; + + NSUInteger start = 0, length = keyPath.length, end = length; + for (; end != NSNotFound; start = end + 1) { + end = [keyPath rangeOfString:@"." options:0 range:{start, length - start}].location; + RLMPrecondition(end == NSNotFound || end + 1 < length, @"Invalid predicate", + @"Invalid keypath '%@': no key name after last '.'", keyPath); + RLMPrecondition(end > start, @"Invalid predicate", + @"Invalid keypath '%@': no key name before '.'", keyPath); + + NSString *propertyName = [keyPath substringWithRange:{start, end == NSNotFound ? length - start : end - start}]; + + if ([propertyName characterAtIndex:0] == '@') { + if ([propertyName isEqualToString:@"@allValues"]) { + RLMPrecondition(property.dictionary, @"Invalid predicate", + @"Invalid keypath '%@': @allValues must follow a dictionary property.", keyPath); + continue; + } + RLMPrecondition(collectionOperation == CollectionOperation::None, @"Invalid predicate", + @"Invalid keypath '%@': at most one collection operation per keypath is supported.", keyPath); + collectionOperation = CollectionOperation::type_for_name(propertyName); + RLMPrecondition(collectionOperation != CollectionOperation::None, @"Invalid predicate", + @"Invalid keypath '%@': Unsupported collection operation '%@'", keyPath, propertyName); + + RLMPrecondition(property.collection, @"Invalid predicate", + @"Invalid keypath '%@': collection operation '%@' must be applied to a collection", keyPath, propertyName); + switch (collectionOperation) { + case CollectionOperation::None: + REALM_UNREACHABLE(); + case CollectionOperation::Count: + RLMPrecondition(end == NSNotFound, @"Invalid predicate", + @"Invalid keypath '%@': @count must appear at the end of a keypath.", keyPath); + break; + case CollectionOperation::AllKeys: + RLMPrecondition(end == NSNotFound, @"Invalid predicate", + @"Invalid keypath '%@': @allKeys must appear at the end of a keypath.", keyPath); + RLMPrecondition(property.dictionary, @"Invalid predicate", + @"Invalid keypath '%@': @allKeys must follow a dictionary property.", keyPath); + break; + default: + if (propertyTypeIsLink(property.type)) { + RLMPrecondition(end != NSNotFound, @"Invalid predicate", + @"Invalid keypath '%@': %@ on a collection of objects cannot appear at the end of a keypath.", keyPath, propertyName); + } + else { + RLMPrecondition(end == NSNotFound, @"Invalid predicate", + @"Invalid keypath '%@': %@ on a collection of values must appear at the end of a keypath.", keyPath, propertyName); + RLMPrecondition(propertyTypeIsNumeric(property.type), @"Invalid predicate", + @"Invalid keypath '%@': %@ can only be applied to a collection of numeric values.", keyPath, propertyName); + } + } + collectionOperationName = propertyName; + continue; + } + + RLMPrecondition(objectSchema, @"Invalid predicate", + @"Invalid keypath '%@': %@ property %@ can only be followed by a collection operation.", + keyPath, property.typeName, property.name); + + property = objectSchema[propertyName]; + RLMPrecondition(property, @"Invalid predicate", + @"Invalid keypath '%@': Property '%@' not found in object of type '%@'", + keyPath, propertyName, objectSchema.className); + RLMPrecondition(collectionOperation == CollectionOperation::None || (propertyTypeIsNumeric(property.type) && !property.collection), + @"Invalid predicate", + @"Invalid keypath '%@': %@ must be followed by a numeric property.", keyPath, collectionOperationName); + + if (property.collection) + keyPathContainsToManyRelationship = true; + + links.push_back(property); + + if (end != NSNotFound) { + RLMPrecondition(property.type == RLMPropertyTypeObject || property.type == RLMPropertyTypeLinkingObjects || property.collection, + @"Invalid predicate", @"Invalid keypath '%@': Property '%@.%@' is not a link or collection and can only appear at the end of a keypath.", + keyPath, objectSchema.className, propertyName); + objectSchema = property.objectClassName ? schema[property.objectClassName] : nil; + } + }; + + links.pop_back(); + return {std::move(links), property, collectionOperation, keyPathContainsToManyRelationship}; +} + +ColumnReference QueryBuilder::column_reference_from_key_path(KeyPath&& kp, bool isAggregate) +{ + if (isAggregate && !kp.containsToManyRelationship) { + throwException(@"Invalid predicate", + @"Aggregate operations can only be used on key paths that include an collection property"); + } else if (!isAggregate && kp.containsToManyRelationship) { + throwException(@"Invalid predicate", + @"Key paths that include a collection property must use aggregate operations"); + } + + return ColumnReference(m_query, m_group, m_schema, kp.property, std::move(kp.links)); +} + +#pragma mark Collection Operations + +// static_assert is always evaluated even if it's inside a if constexpr +// unless the value is derived from the template argument, in which case it's +// only evaluated if that branch is active +template struct AlwaysFalse : std::false_type {}; + +template +auto collection_operation_expr_2(Column&& column) { + if constexpr (OperationType == CollectionOperation::Minimum) { + return column.min(); + } + else if constexpr (OperationType == CollectionOperation::Maximum) { + return column.max(); + } + else if constexpr (OperationType == CollectionOperation::Sum) { + return column.sum(); + } + else if constexpr (OperationType == CollectionOperation::Average) { + return column.average(); + } + else { + static_assert(AlwaysFalse::value, "invalid operation type"); + } +} + +template +auto collection_operation_expr(CollectionOperation operation) { + REALM_ASSERT(operation.type() == OperationType); + + if constexpr (IsLinkCollection) { + auto&& resolved = operation.link_column().resolve(); + auto col = operation.column().column(); + return collection_operation_expr_2(resolved.template column(col)); + } + else if constexpr (IsDictionary) { + return collection_operation_expr_2(operation.link_column().resolve()); + } + else { + return collection_operation_expr_2(operation.link_column().resolve>()); + } +} + +template +void QueryBuilder::add_collection_operation_constraint(NSPredicateOperatorType operatorType, + CollectionOperation const& collectionOperation, R&& rhs, + NSComparisonPredicateOptions) +{ + auto type = IsLinkCollection ? collectionOperation.column().type() : collectionOperation.link_column().type(); + + switch (type) { + case RLMPropertyTypeInt: + add_numeric_constraint(type, operatorType, + collection_operation_expr(collectionOperation), + value_of_type(rhs)); + break; + case RLMPropertyTypeFloat: + add_numeric_constraint(type, operatorType, + collection_operation_expr(collectionOperation), + value_of_type(rhs)); + break; + case RLMPropertyTypeDouble: + add_numeric_constraint(type, operatorType, + collection_operation_expr(collectionOperation), + value_of_type(rhs)); + break; + case RLMPropertyTypeDecimal128: + add_numeric_constraint(type, operatorType, + collection_operation_expr(collectionOperation), + value_of_type(rhs)); + break; + case RLMPropertyTypeDate: + if constexpr (Operation == CollectionOperation::Sum || Operation == CollectionOperation::Average) { + throwException(@"Unsupported predicate value type", + @"Cannot sum or average date properties"); + } + else { + add_numeric_constraint(type, operatorType, + collection_operation_expr(collectionOperation), + value_of_type(rhs)); + } + break; + case RLMPropertyTypeAny: + add_numeric_constraint(type, operatorType, + collection_operation_expr(collectionOperation), + value_of_type(rhs)); + break; + default: + REALM_ASSERT(false && "Only numeric property types should hit this path."); + } +} + +template +void QueryBuilder::add_collection_operation_constraint(NSPredicateOperatorType operatorType, + CollectionOperation const& collectionOperation, R&& rhs, + NSComparisonPredicateOptions options) +{ + convert_null(rhs, [&](auto&& rhs) { + if (collectionOperation.link_column().is_link()) { + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), options); + } + else if (collectionOperation.column().property().dictionary) { + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), options); + } + else { + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), options); + } + }); +} + +template +void get_collection_type(__unsafe_unretained RLMProperty *prop, Fn&& fn) { + if (prop.array) { + fn((Lst*)0); + } + else if (prop.set) { + fn((Set*)0); + } + else { + fn((Dictionary*)0); + } +} + +template +void QueryBuilder::add_collection_operation_constraint(NSPredicateOperatorType operatorType, + CollectionOperation const& collectionOperation, R&& rhs, + NSComparisonPredicateOptions comparisonOptions) +{ + switch (collectionOperation.type()) { + case CollectionOperation::None: + break; + case CollectionOperation::Count: { + auto& column = collectionOperation.link_column(); + RLMPropertyType type = column.type(); + auto rhsValue = value_of_type(rhs); + auto continuation = [&](auto t) { + add_numeric_constraint(type, operatorType, column.resolve>().size(), rhsValue); + }; + + switch (type) { + case RLMPropertyTypeBool: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeObjectId: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeDate: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeDouble: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeFloat: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeInt: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeDecimal128: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeString: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeData: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeUUID: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeAny: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeObject: + case RLMPropertyTypeLinkingObjects: + return add_numeric_constraint(type, operatorType, column.resolve().count(), rhsValue); + } + } + case CollectionOperation::Minimum: + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), comparisonOptions); + break; + case CollectionOperation::Maximum: + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), comparisonOptions); + break; + case CollectionOperation::Sum: + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), comparisonOptions); + break; + case CollectionOperation::Average: + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), comparisonOptions); + break; + case CollectionOperation::AllKeys: { + // BETWEEN and IN are not supported by @allKeys as the parsing for collection + // operators happens before and disection of a rhs array of values. + add_string_constraint(operatorType, comparisonOptions, + Columns(collectionOperation.link_column().column(), m_query.get_table()).keys(), + value_of_type(rhs)); + break; + } + } +} + +bool key_path_contains_collection_operator(const KeyPath& kp) { + return kp.collectionOperation != CollectionOperation::None; +} + +CollectionOperation QueryBuilder::collection_operation_from_key_path(KeyPath&& kp) { + // Collection operations can either come at the end, or immediately before + // the last property. Count and AllKeys are always the end, while + // min/max/sum/avg are at the end for collections of primitives and one + // before the end for collections of objects (with the aggregate done on a + // property of those objects). For one-before-the-end we need to construct + // a KeyPath to both the final link and the final property. + KeyPath linkPrefix = kp; + if (kp.collectionOperation != CollectionOperation::Count && kp.collectionOperation != CollectionOperation::AllKeys && !kp.property.collection) { + REALM_ASSERT(!kp.links.empty()); + linkPrefix.property = linkPrefix.links.back(); + linkPrefix.links.pop_back(); + } + return CollectionOperation(kp.collectionOperation, column_reference_from_key_path(std::move(linkPrefix), true), + column_reference_from_key_path(std::move(kp), true)); +} + +NSPredicateOperatorType invert_comparison_operator(NSPredicateOperatorType type) { + switch (type) { + case NSLessThanPredicateOperatorType: + return NSGreaterThanPredicateOperatorType; + case NSLessThanOrEqualToPredicateOperatorType: + return NSGreaterThanOrEqualToPredicateOperatorType; + case NSGreaterThanPredicateOperatorType: + return NSLessThanPredicateOperatorType; + case NSGreaterThanOrEqualToPredicateOperatorType: + return NSLessThanOrEqualToPredicateOperatorType; + case NSBeginsWithPredicateOperatorType: + case NSEndsWithPredicateOperatorType: + case NSContainsPredicateOperatorType: + case NSLikePredicateOperatorType: + throwException(@"Unsupported predicate", @"Operator '%@' requires a keypath on the left side.", operatorName(type)); + default: + return type; + } +} + +void QueryBuilder::apply_collection_operator_expression(KeyPath&& kp, id value, + NSComparisonPredicate *pred) { + CollectionOperation operation = collection_operation_from_key_path(std::move(kp)); + operation.validate_comparison(value); + + auto type = pred.predicateOperatorType; + if (pred.leftExpression.expressionType != NSKeyPathExpressionType) { + // Turn "a > b" into "b < a" so that we can always put the column on the lhs + type = invert_comparison_operator(type); + } + add_collection_operation_constraint(type, operation, value, pred.options); +} + +void QueryBuilder::apply_value_expression(KeyPath&& kp, id value, NSComparisonPredicate *pred) +{ + if (key_path_contains_collection_operator(kp)) { + apply_collection_operator_expression(std::move(kp), value, pred); + return; + } + + bool isAny = pred.comparisonPredicateModifier == NSAnyPredicateModifier; + ColumnReference column = column_reference_from_key_path(std::move(kp), isAny); + + // check to see if this is a between query + if (pred.predicateOperatorType == NSBetweenPredicateOperatorType) { + add_between_constraint(std::move(column), value); + return; + } + + // turn "key.path IN collection" into ored together ==. "collection IN key.path" is handled elsewhere. + if (pred.predicateOperatorType == NSInPredicateOperatorType) { + process_or_group(m_query, value, [&](id item) { + id normalized = value_from_constant_expression_or_value(item); + column.validate_comparison(normalized); + add_constraint(NSEqualToPredicateOperatorType, pred.options, column, normalized); + }); + return; + } + + column.validate_comparison(value); + if (pred.leftExpression.expressionType == NSKeyPathExpressionType) { + add_constraint(pred.predicateOperatorType, pred.options, std::move(column), value); + } else { + add_constraint(invert_comparison_operator(pred.predicateOperatorType), pred.options, std::move(column), value); + } +} + +void QueryBuilder::apply_column_expression(KeyPath&& leftKeyPath, KeyPath&& rightKeyPath, NSComparisonPredicate *predicate) +{ + bool left_key_path_contains_collection_operator = key_path_contains_collection_operator(leftKeyPath); + bool right_key_path_contains_collection_operator = key_path_contains_collection_operator(rightKeyPath); + if (left_key_path_contains_collection_operator && right_key_path_contains_collection_operator) { + throwException(@"Unsupported predicate", @"Key paths including aggregate operations cannot be compared with other aggregate operations."); + } + + if (left_key_path_contains_collection_operator) { + CollectionOperation left = collection_operation_from_key_path(std::move(leftKeyPath)); + ColumnReference right = column_reference_from_key_path(std::move(rightKeyPath), false); + left.validate_comparison(right); + add_collection_operation_constraint(predicate.predicateOperatorType, std::move(left), std::move(right), predicate.options); + return; + } + if (right_key_path_contains_collection_operator) { + ColumnReference left = column_reference_from_key_path(std::move(leftKeyPath), false); + CollectionOperation right = collection_operation_from_key_path(std::move(rightKeyPath)); + right.validate_comparison(left); + add_collection_operation_constraint(invert_comparison_operator(predicate.predicateOperatorType), + std::move(right), std::move(left), predicate.options); + return; + } + + bool isAny = false; + ColumnReference left = column_reference_from_key_path(std::move(leftKeyPath), isAny); + ColumnReference right = column_reference_from_key_path(std::move(rightKeyPath), isAny); + + // NOTE: It's assumed that column type must match and no automatic type conversion is supported. + RLMPrecondition(left.type() == right.type(), + RLMPropertiesComparisonTypeMismatchException, + RLMPropertiesComparisonTypeMismatchReason, + RLMTypeToString(left.type()), + RLMTypeToString(right.type())); + + // TODO: Should we handle special case where left row is the same as right row (tautology) + add_constraint(predicate.predicateOperatorType, predicate.options, + std::move(left), std::move(right)); +} + +// Identify expressions of the form [SELF valueForKeyPath:] +bool is_self_value_for_key_path_function_expression(NSExpression *expression) +{ + if (expression.expressionType != NSFunctionExpressionType) + return false; + + if (expression.operand.expressionType != NSEvaluatedObjectExpressionType) + return false; + + return [expression.function isEqualToString:@"valueForKeyPath:"]; +} + +// -[NSPredicate predicateWithSubtitutionVariables:] results in function expressions of the form [SELF valueForKeyPath:] +// that apply_predicate cannot handle. Replace such expressions with equivalent NSKeyPathExpressionType expressions. +NSExpression *simplify_self_value_for_key_path_function_expression(NSExpression *expression) { + if (is_self_value_for_key_path_function_expression(expression)) { + if (NSString *keyPath = [expression.arguments.firstObject keyPath]) { + return [NSExpression expressionForKeyPath:keyPath]; + } + } + return expression; +} + +void QueryBuilder::apply_map_expression(RLMObjectSchema *objectSchema, NSExpression *functionExpression, + NSComparisonPredicateOptions options, NSPredicateOperatorType operatorType, + NSExpression *right) { + NSString *keyPath; + NSString *mapKey; + if (functionExpression.operand.expressionType == NSKeyPathExpressionType) { + NSExpression *mapItems = [functionExpression.arguments firstObject]; + NSExpression *linkCol = [[functionExpression.operand arguments] firstObject]; + NSExpression *mapCol = [mapItems.arguments firstObject]; + mapKey = [mapItems.arguments[1] constantValue]; + keyPath = [NSString stringWithFormat:@"%@.%@", linkCol.keyPath, mapCol.keyPath]; + } else { + keyPath = [functionExpression.arguments.firstObject keyPath]; + mapKey = [functionExpression.arguments[1] constantValue]; + } + + ColumnReference collectionColumn = column_reference_from_key_path(key_path_from_string(m_schema, objectSchema, keyPath), true); + RLMPrecondition(collectionColumn.property().dictionary, @"Invalid predicate", + @"Invalid keypath '%@': only dictionaries support subscript predicates.", functionExpression); + add_mixed_constraint(operatorType, options, collectionColumn.resolve().key(mapKey.UTF8String), right.constantValue); +} + +void QueryBuilder::apply_function_expression(RLMObjectSchema *objectSchema, NSExpression *functionExpression, + NSPredicateOperatorType operatorType, NSExpression *right) { + RLMPrecondition(functionExpression.operand.expressionType == NSSubqueryExpressionType, + @"Invalid predicate", @"The '%@' function is not supported.", functionExpression.function); + RLMPrecondition([functionExpression.function isEqualToString:@"valueForKeyPath:"] && functionExpression.arguments.count == 1, + @"Invalid predicate", @"The '%@' function is not supported on the result of a SUBQUERY.", functionExpression.function); + + NSExpression *keyPathExpression = functionExpression.arguments.firstObject; + RLMPrecondition([keyPathExpression.keyPath isEqualToString:@"@count"], + @"Invalid predicate", @"SUBQUERY is only supported when immediately followed by .@count that is compared with a constant number."); + RLMPrecondition(right.expressionType == NSConstantValueExpressionType && [right.constantValue isKindOfClass:[NSNumber class]], + @"Invalid predicate expression", @"SUBQUERY(…).@count is only supported when compared with a constant number."); + + NSExpression *subqueryExpression = functionExpression.operand; + int64_t value = [right.constantValue integerValue]; + + ColumnReference collectionColumn = column_reference_from_key_path(key_path_from_string(m_schema, objectSchema, [subqueryExpression.collection keyPath]), true); + RLMObjectSchema *collectionMemberObjectSchema = m_schema[collectionColumn.property().objectClassName]; + + // Eliminate references to the iteration variable in the subquery. + NSPredicate *subqueryPredicate = [subqueryExpression.predicate predicateWithSubstitutionVariables:@{subqueryExpression.variable: [NSExpression expressionForEvaluatedObject]}]; + subqueryPredicate = transformPredicate(subqueryPredicate, simplify_self_value_for_key_path_function_expression); + + Query subquery = RLMPredicateToQuery(subqueryPredicate, collectionMemberObjectSchema, m_schema, m_group); + add_numeric_constraint(RLMPropertyTypeInt, operatorType, + collectionColumn.resolve(std::move(subquery)).count(), value); +} + +void QueryBuilder::apply_predicate(NSPredicate *predicate, RLMObjectSchema *objectSchema) +{ + // Compound predicates. + if ([predicate isMemberOfClass:[NSCompoundPredicate class]]) { + NSCompoundPredicate *comp = (NSCompoundPredicate *)predicate; + + switch ([comp compoundPredicateType]) { + case NSAndPredicateType: + if (comp.subpredicates.count) { + // Add all of the subpredicates. + m_query.group(); + for (NSPredicate *subp in comp.subpredicates) { + apply_predicate(subp, objectSchema); + } + m_query.end_group(); + } else { + // NSCompoundPredicate's documentation states that an AND predicate with no subpredicates evaluates to TRUE. + m_query.and_query(std::unique_ptr(new TrueExpression)); + } + break; + + case NSOrPredicateType: { + // Add all of the subpredicates with ors inbetween. + process_or_group(m_query, comp.subpredicates, [&](__unsafe_unretained NSPredicate *const subp) { + apply_predicate(subp, objectSchema); + }); + break; + } + + case NSNotPredicateType: + // Add the negated subpredicate + m_query.Not(); + apply_predicate(comp.subpredicates.firstObject, objectSchema); + break; + + default: + // Not actually possible short of users making their own weird + // broken subclass of NSPredicate + throwException(@"Invalid compound predicate type", + @"Only AND, OR, and NOT compound predicates are supported"); + } + } + else if ([predicate isMemberOfClass:[NSComparisonPredicate class]]) { + NSComparisonPredicate *compp = (NSComparisonPredicate *)predicate; + + RLMPrecondition(compp.comparisonPredicateModifier != NSAllPredicateModifier, + @"Invalid predicate", @"ALL modifier not supported"); + + NSExpressionType exp1Type = compp.leftExpression.expressionType; + NSExpressionType exp2Type = compp.rightExpression.expressionType; + + if (compp.predicateOperatorType == NSBetweenPredicateOperatorType || compp.predicateOperatorType == NSInPredicateOperatorType) { + // Inserting an array via %@ gives NSConstantValueExpressionType, but including it directly gives NSAggregateExpressionType + if (exp1Type == NSKeyPathExpressionType && (exp2Type == NSAggregateExpressionType || exp2Type == NSConstantValueExpressionType)) { + // "key.path IN %@", "key.path IN {…}", "key.path BETWEEN %@", or "key.path BETWEEN {…}". + exp2Type = NSConstantValueExpressionType; + } + else if (compp.predicateOperatorType == NSInPredicateOperatorType && exp1Type == NSConstantValueExpressionType && exp2Type == NSKeyPathExpressionType) { + // "%@ IN key.path" is equivalent to "ANY key.path IN %@". Rewrite the former into the latter. + compp = [NSComparisonPredicate predicateWithLeftExpression:compp.rightExpression rightExpression:compp.leftExpression + modifier:NSAnyPredicateModifier type:NSEqualToPredicateOperatorType options:0]; + exp1Type = NSKeyPathExpressionType; + exp2Type = NSConstantValueExpressionType; + } + else { + if (compp.predicateOperatorType == NSBetweenPredicateOperatorType) { + throwException(@"Invalid predicate", + @"Predicate with BETWEEN operator must compare a KeyPath with an aggregate with two values"); + } + else if (compp.predicateOperatorType == NSInPredicateOperatorType) { + throwException(@"Invalid predicate", + @"Predicate with IN operator must compare a KeyPath with an aggregate"); + } + } + } + + if (exp1Type == NSKeyPathExpressionType && exp2Type == NSKeyPathExpressionType) { + // both expression are KeyPaths + apply_column_expression(key_path_from_string(m_schema, objectSchema, compp.leftExpression.keyPath), + key_path_from_string(m_schema, objectSchema, compp.rightExpression.keyPath), + compp); + } + else if (exp1Type == NSKeyPathExpressionType && exp2Type == NSConstantValueExpressionType) { + // comparing keypath to value + apply_value_expression(key_path_from_string(m_schema, objectSchema, compp.leftExpression.keyPath), + compp.rightExpression.constantValue, compp); + } + else if (exp1Type == NSConstantValueExpressionType && exp2Type == NSKeyPathExpressionType) { + // comparing value to keypath + apply_value_expression(key_path_from_string(m_schema, objectSchema, compp.rightExpression.keyPath), + compp.leftExpression.constantValue, compp); + } + else if (exp1Type == NSFunctionExpressionType) { + if (compp.leftExpression.operand.expressionType == NSSubqueryExpressionType) { + apply_function_expression(objectSchema, compp.leftExpression, compp.predicateOperatorType, compp.rightExpression); + } else { + apply_map_expression(objectSchema, compp.leftExpression, compp.options, compp.predicateOperatorType, compp.rightExpression); + } + } + else if (exp1Type == NSSubqueryExpressionType) { + // The subquery expressions that we support are handled by the NSFunctionExpressionType case above. + throwException(@"Invalid predicate expression", @"SUBQUERY is only supported when immediately followed by .@count."); + } + else { + throwException(@"Invalid predicate expressions", + @"Predicate expressions must compare a keypath and another keypath or a constant value"); + } + } + else if ([predicate isEqual:[NSPredicate predicateWithValue:YES]]) { + m_query.and_query(std::unique_ptr(new TrueExpression)); + } else if ([predicate isEqual:[NSPredicate predicateWithValue:NO]]) { + m_query.and_query(std::unique_ptr(new FalseExpression)); + } + else { + // invalid predicate type + throwException(@"Invalid predicate", + @"Only support compound, comparison, and constant predicates"); + } +} +} // namespace + +realm::Query RLMPredicateToQuery(NSPredicate *predicate, RLMObjectSchema *objectSchema, + RLMSchema *schema, Group &group) +{ + auto query = get_table(group, objectSchema).where(); + + // passing a nil predicate is a no-op + if (!predicate) { + return query; + } + + try { + @autoreleasepool { + QueryBuilder(query, group, schema).apply_predicate(predicate, objectSchema); + } + } + catch (std::exception const& e) { + @throw RLMException(e); + } + + return query; +} + +// return the property for a validated column name +RLMProperty *RLMValidatedProperty(RLMObjectSchema *desc, NSString *columnName) { + RLMProperty *prop = desc[columnName]; + RLMPrecondition(prop, @"Invalid property name", + @"Property '%@' not found in object of type '%@'", columnName, desc.className); + return prop; +} diff --git a/Pods/Realm/Realm/RLMRealm+Sync.mm b/Pods/Realm/Realm/RLMRealm+Sync.mm new file mode 100644 index 0000000..9ee8b0a --- /dev/null +++ b/Pods/Realm/Realm/RLMRealm+Sync.mm @@ -0,0 +1,40 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2017 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMRealm+Sync.h" + +#import "RLMObjectBase.h" +#import "RLMQueryUtil.hpp" +#import "RLMObjectSchema.h" +#import "RLMRealm_Private.hpp" +#import "RLMResults_Private.hpp" +#import "RLMSchema.h" +#import "RLMSyncSession.h" + +#import +#import + +using namespace realm; + +@implementation RLMRealm (Sync) + +- (RLMSyncSession *)syncSession { + return [RLMSyncSession sessionForRealm:self]; +} + +@end diff --git a/Pods/Realm/Realm/RLMRealm.mm b/Pods/Realm/Realm/RLMRealm.mm new file mode 100644 index 0000000..9109d0e --- /dev/null +++ b/Pods/Realm/Realm/RLMRealm.mm @@ -0,0 +1,1152 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMRealm_Private.hpp" + +#import "RLMAnalytics.hpp" +#import "RLMAsyncTask_Private.h" +#import "RLMArray_Private.hpp" +#import "RLMDictionary_Private.hpp" +#import "RLMError_Private.hpp" +#import "RLMLogger.h" +#import "RLMMigration_Private.h" +#import "RLMObject_Private.h" +#import "RLMObject_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObservation.hpp" +#import "RLMProperty.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMRealmUtil.hpp" +#import "RLMScheduler.h" +#import "RLMSchema_Private.hpp" +#import "RLMSyncConfiguration.h" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMSet_Private.hpp" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUpdateChecker.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import +#import +#import +#import +#import +#import + +#if REALM_ENABLE_SYNC +#import "RLMSyncManager_Private.hpp" +#import "RLMSyncSession_Private.hpp" +#import "RLMSyncUtil_Private.hpp" +#import "RLMSyncSubscription_Private.hpp" + +#import +#endif + +using namespace realm; +using util::File; + +@interface RLMRealmNotificationToken : RLMNotificationToken +@property (nonatomic, strong) RLMRealm *realm; +@property (nonatomic, copy) RLMNotificationBlock block; +@end + +@interface RLMRealm () +@property (nonatomic, strong) NSHashTable *notificationHandlers; +- (void)sendNotifications:(RLMNotification)notification; +@end + +void RLMDisableSyncToDisk() { + realm::disable_sync_to_disk(); +} + +static std::atomic s_set_skip_backup_attribute{true}; +void RLMSetSkipBackupAttribute(bool value) { + s_set_skip_backup_attribute = value; +} + +static void RLMAddSkipBackupAttributeToItemAtPath(std::string_view path) { + [[NSURL fileURLWithPath:@(path.data())] setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil]; +} + +void RLMWaitForRealmToClose(NSString *path) { + NSString *lockfilePath = [path stringByAppendingString:@".lock"]; + File lockfile(lockfilePath.UTF8String, File::mode_Update); + lockfile.set_fifo_path([path stringByAppendingString:@".management"].UTF8String, "lock.fifo"); + while (!lockfile.try_rw_lock_exclusive()) { + sched_yield(); + } +} + +BOOL RLMIsRealmCachedAtPath(NSString *path) { + return RLMGetAnyCachedRealmForPath([path cStringUsingEncoding:NSUTF8StringEncoding]) != nil; +} + +RLM_HIDDEN +@implementation RLMRealmNotificationToken +- (bool)invalidate { + if (_realm) { + [_realm verifyThread]; + [_realm.notificationHandlers removeObject:self]; + _realm = nil; + _block = nil; + return true; + } + return false; +} + +- (void)suppressNextNotification { + // Temporarily replace the block with one which restores the old block + // rather than producing a notification. + + // This briefly creates a retain cycle but it's fine because the block will + // be synchronously called shortly after this method is called. Unlike with + // collection notifications, this does not have to go through the object + // store or do fancy things to handle transaction coalescing because it's + // called synchronously by the obj-c code and not by the object store. + auto notificationBlock = _block; + _block = ^(RLMNotification, RLMRealm *) { + _block = notificationBlock; + }; +} + +- (void)dealloc { + if (_realm || _block) { + NSLog(@"RLMNotificationToken released without unregistering a notification. You must hold " + @"on to the RLMNotificationToken returned from addNotificationBlock and call " + @"-[RLMNotificationToken invalidate] when you no longer wish to receive RLMRealm notifications."); + } +} +@end + +static bool shouldForciblyDisableEncryption() { + static bool disableEncryption = getenv("REALM_DISABLE_ENCRYPTION"); + return disableEncryption; +} + +NSData *RLMRealmValidatedEncryptionKey(NSData *key) { + if (shouldForciblyDisableEncryption()) { + return nil; + } + + if (key && key.length != 64) { + @throw RLMException(@"Encryption key must be exactly 64 bytes long"); + } + + return key; +} + +REALM_NOINLINE void RLMRealmTranslateException(NSError **error) { + try { + throw; + } + catch (FileAccessError const& ex) { + RLMSetErrorOrThrow(makeError(ex), error); + } + catch (Exception const& ex) { + RLMSetErrorOrThrow(makeError(ex), error); + } + catch (std::system_error const& ex) { + RLMSetErrorOrThrow(makeError(ex), error); + } + catch (std::exception const& ex) { + RLMSetErrorOrThrow(makeError(ex), error); + } +} + +namespace { +// ARC tries to eliminate calls to autorelease when the value is then immediately +// returned, but this results in significantly different semantics between debug +// and release builds for RLMRealm, so force it to always autorelease. +// NEXT-MAJOR: we should switch to NS_RETURNS_RETAINED, which did not exist yet +// when we wrote this but is the correct thing. +id autorelease(__unsafe_unretained id value) { + // +1 __bridge_retained, -1 CFAutorelease + return value ? (__bridge id)CFAutorelease((__bridge_retained CFTypeRef)value) : nil; +} + +RLMRealm *getCachedRealm(RLMRealmConfiguration *configuration, RLMScheduler *options) NS_RETURNS_RETAINED { + auto& config = configuration.configRef; + if (!configuration.cache && !configuration.dynamic) { + return nil; + } + + RLMRealm *realm = RLMGetCachedRealm(configuration, options); + if (!realm) { + return nil; + } + + auto const& oldConfig = realm->_realm->config(); + if ((oldConfig.read_only() || oldConfig.immutable()) != configuration.readOnly) { + @throw RLMException(@"Realm at path '%@' already opened with different read permissions", configuration.fileURL.path); + } + if (oldConfig.in_memory != config.in_memory) { + @throw RLMException(@"Realm at path '%@' already opened with different inMemory settings", configuration.fileURL.path); + } + if (realm.dynamic != configuration.dynamic) { + @throw RLMException(@"Realm at path '%@' already opened with different dynamic settings", configuration.fileURL.path); + } + if (oldConfig.encryption_key != config.encryption_key) { + @throw RLMException(@"Realm at path '%@' already opened with different encryption key", configuration.fileURL.path); + } + return autorelease(realm); +} + +bool copySeedFile(RLMRealmConfiguration *configuration, NSError **error) { + if (!configuration.seedFilePath) { + return false; + } + @autoreleasepool { + bool didCopySeed = false; + NSError *copyError; + DB::call_with_lock(configuration.path, [&](auto const&) { + didCopySeed = [[NSFileManager defaultManager] copyItemAtURL:configuration.seedFilePath + toURL:configuration.fileURL + error:©Error]; + }); + if (!didCopySeed && copyError != nil && copyError.code != NSFileWriteFileExistsError) { + RLMSetErrorOrThrow(copyError, error); + return true; + } + } + return false; +} +} // anonymous namespace + +@implementation RLMRealm { + std::mutex _collectionEnumeratorMutex; + NSHashTable *_collectionEnumerators; + bool _sendingNotifications; +} + ++ (void)initialize { + // In cases where we are not using a synced Realm, we initialise the default logger + // before opening any realm. + [RLMLogger class]; +} + ++ (void)runFirstCheckForConfiguration:(RLMRealmConfiguration *)configuration schema:(RLMSchema *)schema { + static bool initialized; + if (initialized) { + return; + } + initialized = true; + + // Run Analytics on the very first any Realm open. + RLMSendAnalytics(configuration, schema); + RLMCheckForUpdates(); +} + +- (instancetype)initPrivate { + self = [super init]; + return self; +} + +- (BOOL)isEmpty { + return realm::ObjectStore::is_empty(self.group); +} + +- (void)verifyThread { + try { + _realm->verify_thread(); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +- (BOOL)inWriteTransaction { + return _realm->is_in_transaction(); +} + +- (realm::Group &)group { + return _realm->read_group(); +} + +- (BOOL)autorefresh { + return _realm->auto_refresh(); +} + +- (void)setAutorefresh:(BOOL)autorefresh { + try { + _realm->set_auto_refresh(autorefresh); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + ++ (instancetype)defaultRealm { + return [RLMRealm realmWithConfiguration:[RLMRealmConfiguration rawDefaultConfiguration] error:nil]; +} + ++ (instancetype)defaultRealmForQueue:(dispatch_queue_t)queue { + return [RLMRealm realmWithConfiguration:[RLMRealmConfiguration rawDefaultConfiguration] + queue:queue error:nil]; +} + ++ (instancetype)realmWithURL:(NSURL *)fileURL { + RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration]; + configuration.fileURL = fileURL; + return [RLMRealm realmWithConfiguration:configuration error:nil]; +} + ++ (RLMAsyncOpenTask *)asyncOpenWithConfiguration:(RLMRealmConfiguration *)configuration + callbackQueue:(dispatch_queue_t)callbackQueue + callback:(RLMAsyncOpenRealmCallback)callback { + return [[RLMAsyncOpenTask alloc] initWithConfiguration:configuration + confinedTo:[RLMScheduler dispatchQueue:callbackQueue] + download:true completion:callback]; +} + ++ (instancetype)realmWithSharedRealm:(SharedRealm)sharedRealm + schema:(RLMSchema *)schema + dynamic:(bool)dynamic { + RLMRealm *realm = [[RLMRealm alloc] initPrivate]; + realm->_realm = sharedRealm; + realm->_dynamic = dynamic; + realm->_schema = schema; + if (!dynamic) { + realm->_realm->set_schema_subset(schema.objectStoreCopy); + } + realm->_info = RLMSchemaInfo(realm); + return autorelease(realm); +} + ++ (instancetype)realmWithSharedRealm:(std::shared_ptr)osRealm + schema:(RLMSchema *)schema + dynamic:(bool)dynamic + freeze:(bool)freeze { + RLMRealm *realm = [[RLMRealm alloc] initPrivate]; + realm->_realm = osRealm; + realm->_dynamic = dynamic; + + if (dynamic) { + realm->_schema = schema ?: [RLMSchema dynamicSchemaFromObjectStoreSchema:osRealm->schema()]; + } + else @autoreleasepool { + if (auto cachedRealm = RLMGetAnyCachedRealmForPath(osRealm->config().path)) { + realm->_realm->set_schema_subset(cachedRealm->_realm->schema()); + realm->_schema = cachedRealm.schema; + realm->_info = cachedRealm->_info.clone(cachedRealm->_realm->schema(), realm); + } + else if (osRealm->is_frozen()) { + realm->_schema = schema ?: RLMSchema.sharedSchema; + realm->_realm->set_schema_subset(realm->_schema.objectStoreCopy); + } + else { + realm->_schema = schema ?: RLMSchema.sharedSchema; + try { + // No migration function: currently this is only used as part of + // client resets on sync Realms, so none is needed. If that + // changes, this'll need to as well. + realm->_realm->update_schema(realm->_schema.objectStoreCopy, osRealm->config().schema_version); + } + catch (...) { + RLMRealmTranslateException(nil); + REALM_COMPILER_HINT_UNREACHABLE(); + } + } + } + + if (realm->_info.begin() == realm->_info.end()) { + realm->_info = RLMSchemaInfo(realm); + } + + if (freeze && !realm->_realm->is_frozen()) { + realm->_realm = realm->_realm->freeze(); + } + + return realm; +} + ++ (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration error:(NSError **)error { + return autorelease([self realmWithConfiguration:configuration + confinedTo:RLMScheduler.currentRunLoop + error:error]); +} + ++ (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration + queue:(dispatch_queue_t)queue + error:(NSError **)error { + return autorelease([self realmWithConfiguration:configuration + confinedTo:[RLMScheduler dispatchQueue:queue] + error:error]); +} + ++ (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration + confinedTo:(RLMScheduler *)scheduler + error:(NSError **)error { + // First check if we already have a cached Realm for this config + if (auto realm = getCachedRealm(configuration, scheduler)) { + return realm; + } + + if (copySeedFile(configuration, error)) { + return nil; + } + + bool dynamic = configuration.dynamic; + bool cache = configuration.cache; + + Realm::Config config = configuration.config; + + RLMRealm *realm = [[self alloc] initPrivate]; + realm->_dynamic = dynamic; + realm->_actor = scheduler.actor; + + // protects the realm cache and accessors cache + static auto& initLock = *new RLMUnfairMutex; + std::lock_guard lock(initLock); + + try { + config.scheduler = scheduler.osScheduler; + if (config.scheduler && !config.scheduler->is_on_thread()) { + throw RLMException(@"Realm opened from incorrect dispatch queue."); + } + realm->_realm = Realm::get_shared_realm(config); + } + catch (...) { + RLMRealmTranslateException(error); + return nil; + } + + bool realmIsCached = false; + // if we have a cached realm on another thread we can skip a few steps and + // just grab its schema + @autoreleasepool { + // ensure that cachedRealm doesn't end up in this thread's autorelease pool + if (auto cachedRealm = RLMGetAnyCachedRealmForPath(config.path)) { + realm->_realm->set_schema_subset(cachedRealm->_realm->schema()); + realm->_schema = cachedRealm.schema; + realm->_info = cachedRealm->_info.clone(cachedRealm->_realm->schema(), realm); + realmIsCached = true; + } + } + + bool isFirstOpen = false; + if (realm->_schema) { } + else if (dynamic) { + realm->_schema = [RLMSchema dynamicSchemaFromObjectStoreSchema:realm->_realm->schema()]; + realm->_info = RLMSchemaInfo(realm); + } + else { + // set/align schema or perform migration if needed + RLMSchema *schema = configuration.customSchema ?: RLMSchema.sharedSchema; + + MigrationFunction migrationFunction; + auto migrationBlock = configuration.migrationBlock; + if (migrationBlock && configuration.schemaVersion > 0) { + migrationFunction = [=](SharedRealm old_realm, SharedRealm realm, Schema& mutableSchema) { + RLMSchema *oldSchema = [RLMSchema dynamicSchemaFromObjectStoreSchema:old_realm->schema()]; + RLMRealm *oldRealm = [RLMRealm realmWithSharedRealm:old_realm + schema:oldSchema + dynamic:true]; + + // The destination RLMRealm can't just use the schema from the + // SharedRealm because it doesn't have information about whether or + // not a class was defined in Swift, which effects how new objects + // are created + RLMRealm *newRealm = [RLMRealm realmWithSharedRealm:realm + schema:schema.copy + dynamic:true]; + + [[[RLMMigration alloc] initWithRealm:newRealm oldRealm:oldRealm schema:mutableSchema] + execute:migrationBlock objectClass:configuration.migrationObjectClass]; + + oldRealm->_realm = nullptr; + newRealm->_realm = nullptr; + }; + } + + DataInitializationFunction initializationFunction; + if (!configuration.rerunOnOpen && configuration.initialSubscriptions) { + initializationFunction = [&isFirstOpen](SharedRealm) { + isFirstOpen = true; + }; + } + + try { + realm->_realm->update_schema(schema.objectStoreCopy, config.schema_version, + std::move(migrationFunction), std::move(initializationFunction)); + } + catch (...) { + RLMRealmTranslateException(error); + return nil; + } + + realm->_schema = schema; + realm->_info = RLMSchemaInfo(realm); + RLMSchemaEnsureAccessorsCreated(realm.schema); + + if (!configuration.readOnly) { + REALM_ASSERT(!realm->_realm->is_in_read_transaction()); + + if (s_set_skip_backup_attribute) { + RLMAddSkipBackupAttributeToItemAtPath(config.path + ".management"); + RLMAddSkipBackupAttributeToItemAtPath(config.path + ".lock"); + RLMAddSkipBackupAttributeToItemAtPath(config.path + ".note"); + } + } + } + + if (cache) { + RLMCacheRealm(configuration, scheduler, realm); + } + + if (!configuration.readOnly) { + realm->_realm->m_binding_context = RLMCreateBindingContext(realm); + realm->_realm->m_binding_context->realm = realm->_realm; + } + +#if REALM_ENABLE_SYNC + if (isFirstOpen || (configuration.rerunOnOpen && !realmIsCached)) { + RLMSyncSubscriptionSet *subscriptions = realm.subscriptions; + [subscriptions update:^{ + configuration.initialSubscriptions(subscriptions); + }]; + } +#endif + + // Run Analytics and Update checker, this will be run only the first any realm open + [self runFirstCheckForConfiguration:configuration schema:realm.schema]; + + return realm; +} + ++ (void)resetRealmState { + RLMClearRealmCache(); + realm::_impl::RealmCoordinator::clear_cache(); + [RLMRealmConfiguration resetRealmConfigurationState]; +} + +- (void)verifyNotificationsAreSupported:(bool)isCollection { + [self verifyThread]; + if (_realm->config().immutable()) { + @throw RLMException(@"Read-only Realms do not change and do not have change notifications."); + } + if (_realm->is_frozen()) { + @throw RLMException(@"Frozen Realms do not change and do not have change notifications."); + } + if (_realm->config().automatic_change_notifications && !_realm->can_deliver_notifications()) { + @throw RLMException(@"Can only add notification blocks from within runloops."); + } + if (isCollection && _realm->is_in_transaction()) { + @throw RLMException(@"Cannot register notification blocks from within write transactions."); + } +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMNotificationBlock)block { + if (!block) { + @throw RLMException(@"The notification block should not be nil"); + } + [self verifyNotificationsAreSupported:false]; + + _realm->read_group(); + + if (!_notificationHandlers) { + _notificationHandlers = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory]; + } + + RLMRealmNotificationToken *token = [[RLMRealmNotificationToken alloc] init]; + token.realm = self; + token.block = block; + [_notificationHandlers addObject:token]; + return token; +} + +- (void)sendNotifications:(RLMNotification)notification { + NSAssert(!_realm->config().immutable(), @"Read-only realms do not have notifications"); + if (_sendingNotifications) { + return; + } + NSUInteger count = _notificationHandlers.count; + if (count == 0) { + return; + } + + _sendingNotifications = true; + auto cleanup = realm::util::make_scope_exit([&]() noexcept { + _sendingNotifications = false; + }); + + // call this realm's notification blocks + if (count == 1) { + if (auto block = [_notificationHandlers.anyObject block]) { + block(notification, self); + } + } + else { + for (RLMRealmNotificationToken *token in _notificationHandlers.allObjects) { + if (auto block = token.block) { + block(notification, self); + } + } + } +} + +- (RLMRealmConfiguration *)configuration { + RLMRealmConfiguration *configuration = [[RLMRealmConfiguration alloc] init]; + configuration.configRef = _realm->config(); + configuration.dynamic = _dynamic; + configuration.customSchema = _schema; + return configuration; +} + +- (void)beginWriteTransaction { + [self beginWriteTransactionWithError:nil]; +} + +- (BOOL)beginWriteTransactionWithError:(NSError **)error { + try { + _realm->begin_transaction(); + return YES; + } + catch (...) { + RLMRealmTranslateException(error); + return NO; + } +} + +- (void)commitWriteTransaction { + [self commitWriteTransaction:nil]; +} + +- (BOOL)commitWriteTransaction:(NSError **)error { + return [self commitWriteTransactionWithoutNotifying:@[] error:error]; +} + +- (BOOL)commitWriteTransactionWithoutNotifying:(NSArray *)tokens error:(NSError **)error { + for (RLMNotificationToken *token in tokens) { + if (token.realm != self) { + @throw RLMException(@"Incorrect Realm: only notifications for the Realm being modified can be skipped."); + } + [token suppressNextNotification]; + } + + try { + _realm->commit_transaction(); + return YES; + } + catch (...) { + RLMRealmTranslateException(error); + return NO; + } +} + +- (void)transactionWithBlock:(__attribute__((noescape)) void(^)(void))block { + [self transactionWithBlock:block error:nil]; +} + +- (BOOL)transactionWithBlock:(__attribute__((noescape)) void(^)(void))block error:(NSError **)outError { + return [self transactionWithoutNotifying:@[] block:block error:outError]; +} + +- (void)transactionWithoutNotifying:(NSArray *)tokens block:(__attribute__((noescape)) void(^)(void))block { + [self transactionWithoutNotifying:tokens block:block error:nil]; +} + +- (BOOL)transactionWithoutNotifying:(NSArray *)tokens block:(__attribute__((noescape)) void(^)(void))block error:(NSError **)error { + [self beginWriteTransactionWithError:error]; + block(); + if (_realm->is_in_transaction()) { + return [self commitWriteTransactionWithoutNotifying:tokens error:error]; + } + return YES; +} + +- (void)cancelWriteTransaction { + try { + _realm->cancel_transaction(); + } + catch (std::exception &ex) { + @throw RLMException(ex); + } +} + +- (BOOL)isPerformingAsynchronousWriteOperations { + return _realm->is_in_async_transaction(); +} + +- (RLMAsyncTransactionId)beginAsyncWriteTransaction:(void(^)())block { + try { + return _realm->async_begin_transaction(block); + } + catch (std::exception &ex) { + @throw RLMException(ex); + } +} + +- (RLMAsyncTransactionId)commitAsyncWriteTransaction { + try { + return _realm->async_commit_transaction(); + } + catch (...) { + RLMRealmTranslateException(nil); + return 0; + } +} + +- (RLMAsyncWriteTask *)beginAsyncWrite { + try { + auto write = [[RLMAsyncWriteTask alloc] initWithRealm:self]; + write.transactionId = _realm->async_begin_transaction(^{ [write complete:false]; }, true); + return write; + } + catch (std::exception &ex) { + @throw RLMException(ex); + } +} + +- (void)commitAsyncWriteWithGrouping:(bool)allowGrouping + completion:(void(^)(NSError *_Nullable))completion { + [self commitAsyncWriteTransaction:completion allowGrouping:allowGrouping]; +} + +- (RLMAsyncTransactionId)commitAsyncWriteTransaction:(void(^)(NSError *))completionBlock { + return [self commitAsyncWriteTransaction:completionBlock allowGrouping:false]; +} + +- (RLMAsyncTransactionId)commitAsyncWriteTransaction:(nullable void(^)(NSError *))completionBlock + allowGrouping:(BOOL)allowGrouping { + try { + auto completion = [=](std::exception_ptr err) { + @autoreleasepool { + if (!completionBlock) { + std::rethrow_exception(err); + return; + } + if (err) { + try { + std::rethrow_exception(err); + } + catch (...) { + NSError *error; + RLMRealmTranslateException(&error); + completionBlock(error); + } + } else { + completionBlock(nil); + } + } + }; + + if (completionBlock) { + return _realm->async_commit_transaction(completion, allowGrouping); + } + return _realm->async_commit_transaction(nullptr, allowGrouping); + } + catch (...) { + RLMRealmTranslateException(nil); + return 0; + } +} + +- (void)cancelAsyncTransaction:(RLMAsyncTransactionId)asyncTransactionId { + try { + _realm->async_cancel_transaction(asyncTransactionId); + } + catch (std::exception &ex) { + @throw RLMException(ex); + } +} + +- (RLMAsyncTransactionId)asyncTransactionWithBlock:(void(^)())block onComplete:(nullable void(^)(NSError *))completionBlock { + return [self beginAsyncWriteTransaction:^{ + block(); + if (_realm->is_in_transaction()) { + [self commitAsyncWriteTransaction:completionBlock]; + } + }]; +} + +- (RLMAsyncTransactionId)asyncTransactionWithBlock:(void(^)())block { + return [self beginAsyncWriteTransaction:^{ + block(); + if (_realm->is_in_transaction()) { + [self commitAsyncWriteTransaction]; + } + }]; +} + +- (void)invalidate { + if (_realm->is_in_transaction()) { + NSLog(@"WARNING: An RLMRealm instance was invalidated during a write " + "transaction and all pending changes have been rolled back."); + } + + [self detachAllEnumerators]; + + for (auto& objectInfo : _info) { + for (RLMObservationInfo *info : objectInfo.second.observedObjects) { + info->willChange(RLMInvalidatedKey); + } + } + + _realm->invalidate(); + + for (auto& objectInfo : _info) { + for (RLMObservationInfo *info : objectInfo.second.observedObjects) { + info->didChange(RLMInvalidatedKey); + } + } + + if (_realm->is_frozen()) { + _realm->close(); + } +} + +- (nullable id)resolveThreadSafeReference:(RLMThreadSafeReference *)reference { + return [reference resolveReferenceInRealm:self]; +} + +/** + Replaces all string columns in this Realm with a string enumeration column and compacts the + database file. + + Cannot be called from a write transaction. + + Compaction will not occur if other `RLMRealm` instances exist. + + While compaction is in progress, attempts by other threads or processes to open the database will + wait. + + Be warned that resource requirements for compaction is proportional to the amount of live data in + the database. + + Compaction works by writing the database contents to a temporary database file and then replacing + the database with the temporary one. The name of the temporary file is formed by appending + `.tmp_compaction_space` to the name of the database. + + @return YES if the compaction succeeded. + */ +- (BOOL)compact { + // compact() automatically ends the read transaction, but we need to clean + // up cached state and send invalidated notifications when that happens, so + // explicitly end it first unless we're in a write transaction (in which + // case compact() will throw an exception) + if (!_realm->is_in_transaction()) { + [self invalidate]; + } + + try { + return _realm->compact(); + } + catch (std::exception const& ex) { + @throw RLMException(ex); + } +} + +- (void)dealloc { + if (_realm) { + if (_realm->is_in_transaction()) { + [self cancelWriteTransaction]; + NSLog(@"WARNING: An RLMRealm instance was deallocated during a write transaction and all " + "pending changes have been rolled back. Make sure to retain a reference to the " + "RLMRealm for the duration of the write transaction."); + } + } +} + +- (BOOL)refresh { + if (_realm->config().immutable()) { + @throw RLMException(@"Read-only Realms do not change and cannot be refreshed."); + } + try { + return _realm->refresh(); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +- (void)addObject:(__unsafe_unretained RLMObject *const)object { + RLMAddObjectToRealm(object, self, RLMUpdatePolicyError); +} + +- (void)addObjects:(id)objects { + for (RLMObject *obj in objects) { + if (![obj isKindOfClass:RLMObjectBase.class]) { + @throw RLMException(@"Cannot insert objects of type %@ with addObjects:. Only RLMObjects are supported.", + NSStringFromClass(obj.class)); + } + [self addObject:obj]; + } +} + +- (void)addOrUpdateObject:(RLMObject *)object { + // verify primary key + if (!object.objectSchema.primaryKeyProperty) { + @throw RLMException(@"'%@' does not have a primary key and can not be updated", object.objectSchema.className); + } + + RLMAddObjectToRealm(object, self, RLMUpdatePolicyUpdateAll); +} + +- (void)addOrUpdateObjects:(id)objects { + for (RLMObject *obj in objects) { + if (![obj isKindOfClass:RLMObjectBase.class]) { + @throw RLMException(@"Cannot add or update objects of type %@ with addOrUpdateObjects:. Only RLMObjects are" + " supported.", + NSStringFromClass(obj.class)); + } + [self addOrUpdateObject:obj]; + } +} + +- (void)deleteObject:(RLMObject *)object { + RLMDeleteObjectFromRealm(object, self); +} + +- (void)deleteObjects:(id)objects { + id idObjects = objects; + if ([idObjects respondsToSelector:@selector(realm)] + && [idObjects respondsToSelector:@selector(deleteObjectsFromRealm)]) { + if (self != (RLMRealm *)[idObjects realm]) { + @throw RLMException(@"Can only delete objects from the Realm they belong to."); + } + [idObjects deleteObjectsFromRealm]; + return; + } + + if (auto array = RLMDynamicCast(objects)) { + if (array.type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMArray<%@>: only RLMObjects can be deleted.", + RLMTypeToString(array.type)); + } + } + else if (auto set = RLMDynamicCast(objects)) { + if (set.type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMSet<%@>: only RLMObjects can be deleted.", + RLMTypeToString(set.type)); + } + } + else if (auto dictionary = RLMDynamicCast(objects)) { + if (dictionary.type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMDictionary of type %@: only RLMObjects can be deleted.", + RLMTypeToString(dictionary.type)); + } + for (RLMObject *obj in dictionary.allValues) { + RLMDeleteObjectFromRealm(obj, self); + } + return; + } + for (RLMObject *obj in objects) { + if (![obj isKindOfClass:RLMObjectBase.class]) { + @throw RLMException(@"Cannot delete objects of type %@ with deleteObjects:. Only RLMObjects can be deleted.", + NSStringFromClass(obj.class)); + } + RLMDeleteObjectFromRealm(obj, self); + } +} + +- (void)deleteAllObjects { + RLMDeleteAllObjectsFromRealm(self); +} + +- (RLMResults *)allObjects:(NSString *)objectClassName { + return RLMGetObjects(self, objectClassName, nil); +} + +- (RLMResults *)objects:(NSString *)objectClassName where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objects:objectClassName where:predicateFormat args:args]; + va_end(args); + return results; +} + +- (RLMResults *)objects:(NSString *)objectClassName where:(NSString *)predicateFormat args:(va_list)args { + return [self objects:objectClassName withPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (RLMResults *)objects:(NSString *)objectClassName withPredicate:(NSPredicate *)predicate { + return RLMGetObjects(self, objectClassName, predicate); +} + +- (RLMObject *)objectWithClassName:(NSString *)className forPrimaryKey:(id)primaryKey { + return RLMGetObject(self, className, primaryKey); +} + ++ (uint64_t)schemaVersionAtURL:(NSURL *)fileURL encryptionKey:(NSData *)key error:(NSError **)error { + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.fileURL = fileURL; + config.encryptionKey = RLMRealmValidatedEncryptionKey(key); + + uint64_t version = RLMNotVersioned; + try { + version = Realm::get_schema_version(config.configRef); + } + catch (...) { + RLMRealmTranslateException(error); + return version; + } + + if (error && version == realm::ObjectStore::NotVersioned) { + auto msg = [NSString stringWithFormat:@"Realm at path '%@' has not been initialized.", fileURL.path]; + *error = [NSError errorWithDomain:RLMErrorDomain + code:RLMErrorInvalidDatabase + userInfo:@{NSLocalizedDescriptionKey: msg, + NSFilePathErrorKey: fileURL.path}]; + } + return version; +} + ++ (BOOL)performMigrationForConfiguration:(RLMRealmConfiguration *)configuration error:(NSError **)error { + if (RLMGetAnyCachedRealmForPath(configuration.path)) { + @throw RLMException(@"Cannot migrate Realms that are already open."); + } + + NSError *localError; // Prevents autorelease + BOOL success; + @autoreleasepool { + success = [RLMRealm realmWithConfiguration:configuration error:&localError] != nil; + } + if (!success && error) { + *error = localError; // Must set outside pool otherwise will free anyway + } + return success; +} + +- (RLMObject *)createObject:(NSString *)className withValue:(id)value { + return (RLMObject *)RLMCreateObjectInRealmWithValue(self, className, value, RLMUpdatePolicyError); +} + +- (BOOL)writeCopyToURL:(NSURL *)fileURL encryptionKey:(NSData *)key error:(NSError **)error { + RLMRealmConfiguration *configuration = [RLMRealmConfiguration new]; + configuration.fileURL = fileURL; + configuration.encryptionKey = key; + return [self writeCopyForConfiguration:configuration error:error]; +} + +- (BOOL)writeCopyForConfiguration:(RLMRealmConfiguration *)configuration error:(NSError **)error { + try { + _realm->convert(configuration.configRef, false); + return YES; + } + catch (...) { + if (error) { + RLMRealmTranslateException(error); + } + } + return NO; +} + ++ (BOOL)fileExistsForConfiguration:(RLMRealmConfiguration *)config { + return [NSFileManager.defaultManager fileExistsAtPath:config.pathOnDisk]; +} + ++ (BOOL)deleteFilesForConfiguration:(RLMRealmConfiguration *)config error:(NSError **)error { + bool didDeleteAny = false; + try { + realm::Realm::delete_files(config.path, &didDeleteAny); + } + catch (realm::FileAccessError const& e) { + if (error) { + // For backwards compatibility, but this should go away in 11.0 + if (e.code() == realm::ErrorCodes::PermissionDenied) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteNoPermissionError + userInfo:@{NSLocalizedDescriptionKey: @(e.what()), + NSFilePathErrorKey: @(e.get_path().data())}]; + } + else { + RLMRealmTranslateException(error); + } + } + } + catch (...) { + if (error) { + RLMRealmTranslateException(error); + } + } + return didDeleteAny; +} + +- (BOOL)isFrozen { + return _realm->is_frozen(); +} + +- (RLMRealm *)freeze { + [self verifyThread]; + return self.isFrozen ? self : RLMGetFrozenRealmForSourceRealm(self); +} + +- (RLMRealm *)thaw { + [self verifyThread]; + return self.isFrozen ? [RLMRealm realmWithConfiguration:self.configuration error:nil] : self; +} + +- (RLMRealm *)frozenCopy { + try { + RLMRealm *realm = [[RLMRealm alloc] initPrivate]; + realm->_realm = _realm->freeze(); + realm->_realm->read_group(); + realm->_dynamic = _dynamic; + realm->_schema = _schema; + realm->_info = RLMSchemaInfo(realm); + return realm; + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +- (void)registerEnumerator:(RLMFastEnumerator *)enumerator { + std::lock_guard lock(_collectionEnumeratorMutex); + if (!_collectionEnumerators) { + _collectionEnumerators = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory]; + } + [_collectionEnumerators addObject:enumerator]; +} + +- (void)unregisterEnumerator:(RLMFastEnumerator *)enumerator { + std::lock_guard lock(_collectionEnumeratorMutex); + [_collectionEnumerators removeObject:enumerator]; +} + +- (void)detachAllEnumerators { + std::lock_guard lock(_collectionEnumeratorMutex); + for (RLMFastEnumerator *enumerator in _collectionEnumerators) { + [enumerator detach]; + } + _collectionEnumerators = nil; +} + +- (bool)isFlexibleSync { +#if REALM_ENABLE_SYNC + return _realm->config().sync_config && _realm->config().sync_config->flx_sync_requested; +#else + return false; +#endif +} + +- (RLMSyncSubscriptionSet *)subscriptions { +#if REALM_ENABLE_SYNC + if (!self.isFlexibleSync) { + @throw RLMException(@"This Realm was not configured with flexible sync"); + } + return [[RLMSyncSubscriptionSet alloc] initWithSubscriptionSet:_realm->get_latest_subscription_set() realm:self]; +#else + @throw RLMException(@"Realm was not compiled with sync enabled"); +#endif +} +@end diff --git a/Pods/Realm/Realm/RLMRealmConfiguration.mm b/Pods/Realm/Realm/RLMRealmConfiguration.mm new file mode 100644 index 0000000..55d4707 --- /dev/null +++ b/Pods/Realm/Realm/RLMRealmConfiguration.mm @@ -0,0 +1,412 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMRealmConfiguration_Private.h" + +#import "RLMEvent.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMRealm_Private.h" +#import "RLMSchema_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import + +#if REALM_ENABLE_SYNC +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMUser_Private.hpp" + +#import +#import +#import +#else +@class RLMSyncConfiguration; +#endif + +static NSString *const c_RLMRealmConfigurationProperties[] = { + @"fileURL", + @"inMemoryIdentifier", + @"encryptionKey", + @"readOnly", + @"schemaVersion", + @"migrationBlock", + @"deleteRealmIfMigrationNeeded", + @"shouldCompactOnLaunch", + @"dynamic", + @"customSchema", +}; + +static NSString *const c_defaultRealmFileName = @"default.realm"; +RLMRealmConfiguration *s_defaultConfiguration; + +NSString *RLMRealmPathForFileAndBundleIdentifier(NSString *fileName, NSString *bundleIdentifier) { + return [RLMDefaultDirectoryForBundleIdentifier(bundleIdentifier) + stringByAppendingPathComponent:fileName]; +} + +NSString *RLMRealmPathForFile(NSString *fileName) { + static NSString *directory = RLMDefaultDirectoryForBundleIdentifier(nil); + return [directory stringByAppendingPathComponent:fileName]; +} + +@implementation RLMRealmConfiguration { + realm::Realm::Config _config; + RLMSyncErrorReportingBlock _manualClientResetHandler; +} + +- (realm::Realm::Config&)configRef { + return _config; +} + +- (std::string const&)path { + return _config.path; +} + ++ (instancetype)defaultConfiguration { + return [[self rawDefaultConfiguration] copy]; +} + ++ (void)setDefaultConfiguration:(RLMRealmConfiguration *)configuration { + if (!configuration) { + @throw RLMException(@"Cannot set the default configuration to nil."); + } + @synchronized(c_defaultRealmFileName) { + s_defaultConfiguration = [configuration copy]; + } +} + ++ (RLMRealmConfiguration *)rawDefaultConfiguration { + RLMRealmConfiguration *configuration; + @synchronized(c_defaultRealmFileName) { + if (!s_defaultConfiguration) { + s_defaultConfiguration = [[RLMRealmConfiguration alloc] init]; + } + configuration = s_defaultConfiguration; + } + return configuration; +} + ++ (void)resetRealmConfigurationState { + @synchronized(c_defaultRealmFileName) { + s_defaultConfiguration = nil; + } +} + +- (instancetype)init { + self = [super init]; + if (self) { + static NSURL *defaultRealmURL = [NSURL fileURLWithPath:RLMRealmPathForFile(c_defaultRealmFileName)]; + self.fileURL = defaultRealmURL; + self.schemaVersion = 0; + self.cache = YES; + _config.automatically_handle_backlinks_in_migrations = true; + } + + return self; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + RLMRealmConfiguration *configuration = [[[self class] allocWithZone:zone] init]; + configuration->_config = _config; + configuration->_cache = _cache; + configuration->_dynamic = _dynamic; + configuration->_migrationBlock = _migrationBlock; + configuration->_shouldCompactOnLaunch = _shouldCompactOnLaunch; + configuration->_customSchema = _customSchema; + configuration->_eventConfiguration = _eventConfiguration; + configuration->_migrationObjectClass = _migrationObjectClass; + configuration->_initialSubscriptions = _initialSubscriptions; + configuration->_rerunOnOpen = _rerunOnOpen; + return configuration; +} + +- (NSString *)description { + NSMutableString *string = [NSMutableString stringWithFormat:@"%@ {\n", self.class]; + for (NSString *key : c_RLMRealmConfigurationProperties) { + NSString *description = [[self valueForKey:key] description]; + description = [description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]; + + [string appendFormat:@"\t%@ = %@;\n", key, description]; + } + return [string stringByAppendingString:@"}"]; +} + +- (NSURL *)fileURL { + if (_config.in_memory) { + return nil; + } + return [NSURL fileURLWithPath:@(_config.path.c_str())]; +} + +- (void)setFileURL:(NSURL *)fileURL { + NSString *path = fileURL.path; + if (path.length == 0) { + @throw RLMException(@"Realm path must not be empty"); + } + + RLMNSStringToStdString(_config.path, path); + _config.in_memory = false; +} + +- (NSString *)inMemoryIdentifier { + if (!_config.in_memory) { + return nil; + } + return [@(_config.path.c_str()) lastPathComponent]; +} + +- (void)setInMemoryIdentifier:(NSString *)inMemoryIdentifier { + if (inMemoryIdentifier.length == 0) { + @throw RLMException(@"In-memory identifier must not be empty"); + } + _config.sync_config = nullptr; + _seedFilePath = nil; + + RLMNSStringToStdString(_config.path, [NSTemporaryDirectory() stringByAppendingPathComponent:inMemoryIdentifier]); + _config.in_memory = true; +} + +- (void)setSeedFilePath:(NSURL *)seedFilePath { + _seedFilePath = seedFilePath; + if (_seedFilePath) { + _config.in_memory = false; + } +} + +- (NSData *)encryptionKey { + return _config.encryption_key.empty() ? nil : [NSData dataWithBytes:_config.encryption_key.data() length:_config.encryption_key.size()]; +} + +- (void)setEncryptionKey:(NSData * __nullable)encryptionKey { + if (NSData *key = RLMRealmValidatedEncryptionKey(encryptionKey)) { + auto bytes = static_cast(key.bytes); + _config.encryption_key.assign(bytes, bytes + key.length); + } + else { + _config.encryption_key.clear(); + } +} + +- (BOOL)readOnly { + return _config.immutable() || _config.read_only(); +} + +static bool isSync(realm::Realm::Config const& config) { +#if REALM_ENABLE_SYNC + return !!config.sync_config; +#endif + return false; +} + +- (void)updateSchemaMode { + if (self.deleteRealmIfMigrationNeeded) { + if (isSync(_config)) { + @throw RLMException(@"Cannot set 'deleteRealmIfMigrationNeeded' when sync is enabled ('syncConfig' is set)."); + } + } + else if (self.readOnly) { + _config.schema_mode = isSync(_config) ? realm::SchemaMode::ReadOnly : realm::SchemaMode::Immutable; + } + else if (isSync(_config)) { + if (_customSchema) { + _config.schema_mode = realm::SchemaMode::AdditiveExplicit; + } + else { + _config.schema_mode = realm::SchemaMode::AdditiveDiscovered; + } + } + else { + _config.schema_mode = realm::SchemaMode::Automatic; + } +} + +- (void)setReadOnly:(BOOL)readOnly { + if (readOnly) { + if (self.deleteRealmIfMigrationNeeded) { + @throw RLMException(@"Cannot set `readOnly` when `deleteRealmIfMigrationNeeded` is set."); + } else if (self.shouldCompactOnLaunch) { + @throw RLMException(@"Cannot set `readOnly` when `shouldCompactOnLaunch` is set."); + } + _config.schema_mode = isSync(_config) ? realm::SchemaMode::ReadOnly : realm::SchemaMode::Immutable; + } + else if (self.readOnly) { + _config.schema_mode = realm::SchemaMode::Automatic; + [self updateSchemaMode]; + } +} + +- (uint64_t)schemaVersion { + return _config.schema_version; +} + +- (void)setSchemaVersion:(uint64_t)schemaVersion { + if (schemaVersion == RLMNotVersioned) { + @throw RLMException(@"Cannot set schema version to %llu (RLMNotVersioned)", RLMNotVersioned); + } + _config.schema_version = schemaVersion; +} + +- (BOOL)deleteRealmIfMigrationNeeded { + return _config.schema_mode == realm::SchemaMode::SoftResetFile; +} + +- (void)setDeleteRealmIfMigrationNeeded:(BOOL)deleteRealmIfMigrationNeeded { + if (deleteRealmIfMigrationNeeded) { + if (self.readOnly) { + @throw RLMException(@"Cannot set `deleteRealmIfMigrationNeeded` when `readOnly` is set."); + } + if (isSync(_config)) { + @throw RLMException(@"Cannot set 'deleteRealmIfMigrationNeeded' when sync is enabled ('syncConfig' is set)."); + } + _config.schema_mode = realm::SchemaMode::SoftResetFile; + } + else if (self.deleteRealmIfMigrationNeeded) { + _config.schema_mode = realm::SchemaMode::Automatic; + } +} + +- (NSArray *)objectClasses { + return [_customSchema.objectSchema valueForKeyPath:@"objectClass"]; +} + +- (void)setObjectClasses:(NSArray *)objectClasses { + _customSchema = objectClasses ? [RLMSchema schemaWithObjectClasses:objectClasses] : nil; + [self updateSchemaMode]; +} + +- (NSUInteger)maximumNumberOfActiveVersions { + if (_config.max_number_of_active_versions > std::numeric_limits::max()) { + return std::numeric_limits::max(); + } + return static_cast(_config.max_number_of_active_versions); +} + +- (void)setMaximumNumberOfActiveVersions:(NSUInteger)maximumNumberOfActiveVersions { + if (maximumNumberOfActiveVersions == 0) { + _config.max_number_of_active_versions = std::numeric_limits::max(); + } + else { + _config.max_number_of_active_versions = maximumNumberOfActiveVersions; + } +} + +- (void)setDynamic:(bool)dynamic { + _dynamic = dynamic; + self.cache = !dynamic; +} + +- (bool)disableFormatUpgrade { + return _config.disable_format_upgrade; +} + +- (void)setDisableFormatUpgrade:(bool)disableFormatUpgrade { + _config.disable_format_upgrade = disableFormatUpgrade; +} + +- (realm::SchemaMode)schemaMode { + return _config.schema_mode; +} + +- (void)setSchemaMode:(realm::SchemaMode)mode { + _config.schema_mode = mode; +} + +- (NSString *)pathOnDisk { + return @(_config.path.c_str()); +} + +- (void)setShouldCompactOnLaunch:(RLMShouldCompactOnLaunchBlock)shouldCompactOnLaunch { + if (shouldCompactOnLaunch) { + if (_config.immutable()) { + @throw RLMException(@"Cannot set `shouldCompactOnLaunch` when `readOnly` is set."); + } + _config.should_compact_on_launch_function = shouldCompactOnLaunch; + } + else { + _config.should_compact_on_launch_function = nullptr; + } + _shouldCompactOnLaunch = shouldCompactOnLaunch; +} + +- (void)setCustomSchemaWithoutCopying:(RLMSchema *)schema { + _customSchema = schema; +} + +- (bool)disableAutomaticChangeNotifications { + return !_config.automatic_change_notifications; +} + +- (void)setDisableAutomaticChangeNotifications:(bool)disableAutomaticChangeNotifications { + _config.automatic_change_notifications = !disableAutomaticChangeNotifications; +} + +#if REALM_ENABLE_SYNC +- (void)setSyncConfiguration:(RLMSyncConfiguration *)syncConfiguration { + if (syncConfiguration == nil) { + _config.sync_config = nullptr; + return; + } + RLMUser *user = syncConfiguration.user; + if (user.state == RLMUserStateRemoved) { + @throw RLMException(@"Cannot set a sync configuration which has an errored-out user."); + } + + NSAssert(user.identifier, @"Cannot call this method on a user that doesn't have an identifier."); + _config.in_memory = false; + _config.sync_config = std::make_shared(syncConfiguration.rawConfiguration); + _config.path = syncConfiguration.path; + + // The manual client reset handler doesn't exist on the raw config, + // so assign it here. + _manualClientResetHandler = syncConfiguration.manualClientResetHandler; + + [self updateSchemaMode]; +} + +- (RLMSyncConfiguration *)syncConfiguration { + if (!_config.sync_config) { + return nil; + } + RLMSyncConfiguration* syncConfig = [[RLMSyncConfiguration alloc] initWithRawConfig:*_config.sync_config path:_config.path]; + syncConfig.manualClientResetHandler = _manualClientResetHandler; + return syncConfig; +} + +#else // REALM_ENABLE_SYNC +- (RLMSyncConfiguration *)syncConfiguration { + return nil; +} +#endif // REALM_ENABLE_SYNC + +- (realm::Realm::Config)config { + auto config = _config; + if (config.sync_config) { + config.sync_config = std::make_shared(*config.sync_config); + } +#if REALM_ENABLE_SYNC + if (config.sync_config) { + RLMSetConfigInfoForClientResetCallbacks(*config.sync_config, self); + } + if (_eventConfiguration) { + config.audit_config = [_eventConfiguration auditConfigWithRealmConfiguration:self]; + } +#endif + return config; +} + +@end diff --git a/Pods/Realm/Realm/RLMRealmUtil.mm b/Pods/Realm/Realm/RLMRealmUtil.mm new file mode 100644 index 0000000..2fad212 --- /dev/null +++ b/Pods/Realm/Realm/RLMRealmUtil.mm @@ -0,0 +1,279 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMRealmUtil.hpp" + +#import "RLMAsyncTask_Private.h" +#import "RLMObservation.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMScheduler.h" +#import "RLMUtil.hpp" + +#import +#import +#import +#import + +#import + +// Global realm state +static auto& s_realmCacheMutex = *new RLMUnfairMutex; +static auto& s_realmsPerPath = *new std::map(); +static auto& s_frozenRealms = *new std::map(); + +void RLMCacheRealm(__unsafe_unretained RLMRealmConfiguration *const configuration, + RLMScheduler *scheduler, + __unsafe_unretained RLMRealm *const realm) { + auto& path = configuration.path; + auto key = scheduler.cacheKey; + std::lock_guard lock(s_realmCacheMutex); + NSMapTable *realms = s_realmsPerPath[path]; + if (!realms) { + s_realmsPerPath[path] = realms = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsOpaquePersonality|NSPointerFunctionsOpaqueMemory + valueOptions:NSPointerFunctionsWeakMemory]; + } + [realms setObject:realm forKey:(__bridge id)key]; +} + +RLMRealm *RLMGetCachedRealm(__unsafe_unretained RLMRealmConfiguration *const configuration, + RLMScheduler *scheduler) { + auto key = scheduler.cacheKey; + auto& path = configuration.path; + std::lock_guard lock(s_realmCacheMutex); + RLMRealm *realm = [s_realmsPerPath[path] objectForKey:(__bridge id)key]; + if (realm && !realm->_realm->scheduler()->is_on_thread()) { + // We can get here in two cases: if the user is trying to open a + // queue-bound Realm from the wrong queue, or if we have a stale cached + // Realm which is bound to a thread that no longer exists. In the first + // case we'll throw an error later on; in the second we'll just create + // a new RLMRealm and replace the cache entry with one bound to the + // thread that now exists. + realm = nil; + } + return realm; +} + +RLMRealm *RLMGetAnyCachedRealm(__unsafe_unretained RLMRealmConfiguration *const configuration) { + return RLMGetAnyCachedRealmForPath(configuration.path); +} + +RLMRealm *RLMGetAnyCachedRealmForPath(std::string const& path) { + std::lock_guard lock(s_realmCacheMutex); + return [s_realmsPerPath[path] objectEnumerator].nextObject; +} + +void RLMClearRealmCache() { + std::lock_guard lock(s_realmCacheMutex); + s_realmsPerPath.clear(); + s_frozenRealms.clear(); +} + +RLMRealm *RLMGetFrozenRealmForSourceRealm(__unsafe_unretained RLMRealm *const sourceRealm) { + std::lock_guard lock(s_realmCacheMutex); + auto& r = *sourceRealm->_realm; + auto& path = r.config().path; + NSMapTable *realms = s_realmsPerPath[path]; + if (!realms) { + s_realmsPerPath[path] = realms = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsIntegerPersonality|NSPointerFunctionsOpaqueMemory + valueOptions:NSPointerFunctionsWeakMemory]; + } + r.read_group(); + auto version = reinterpret_cast(r.read_transaction_version().version); + RLMRealm *realm = [realms objectForKey:(__bridge id)version]; + if (!realm) { + realm = [sourceRealm frozenCopy]; + [realms setObject:realm forKey:(__bridge id)version]; + } + return realm; +} + +namespace { +void advance_to_ready(realm::Realm& realm) { + if (!realm.auto_refresh()) { + realm.set_auto_refresh(true); + realm.notify(); + realm.set_auto_refresh(false); + } +} + +class RLMNotificationHelper : public realm::BindingContext { +public: + RLMNotificationHelper(RLMRealm *realm) : _realm(realm) { } + + void before_notify() override { + @autoreleasepool { + auto blocks = std::move(_beforeNotify); + _beforeNotify.clear(); + for (auto block : blocks) { + block(); + } + } + } + + void changes_available() override { + @autoreleasepool { + auto realm = _realm; + if (!realm || realm.autorefresh) { + return; + } + + // If an async refresh has been requested, then do that now instead + // of notifying of a pending version available. Note that this will + // recursively call this function and then exit above due to + // autorefresh being true. + if (_refreshHandlers.empty()) { + [realm sendNotifications:RLMRealmRefreshRequiredNotification]; + } + else { + advance_to_ready(*realm->_realm); + } + } + } + + std::vector get_observed_rows() override { + @autoreleasepool { + if (auto realm = _realm) { + [realm detachAllEnumerators]; + return RLMGetObservedRows(realm->_info); + } + return {}; + } + } + + void will_change(std::vector const& observed, + std::vector const& invalidated) override { + @autoreleasepool { + RLMWillChange(observed, invalidated); + } + } + + void did_change(std::vector const& observed, + std::vector const& invalidated, bool version_changed) override { + @autoreleasepool { + __strong auto realm = _realm; + try { + RLMDidChange(observed, invalidated); + if (version_changed) { + [realm sendNotifications:RLMRealmDidChangeNotification]; + } + } + catch (...) { + // This can only be called during a write transaction if it was + // called due to the transaction beginning, so cancel it to ensure + // exceptions thrown here behave the same as exceptions thrown when + // actually beginning the write + if (realm.inWriteTransaction) { + [realm cancelWriteTransaction]; + } + throw; + } + + if (!realm || !version_changed) { + return; + } + auto new_version = realm->_realm->current_transaction_version(); + if (!new_version) { + return; + } + + std::erase_if(_refreshHandlers, [&](auto& handler) { + auto& [target_version, completion] = handler; + if (new_version->version >= target_version) { + completion(true); + return true; + } + return false; + }); + } + } + + void add_before_notify_block(dispatch_block_t block) { + _beforeNotify.push_back(block); + } + + void wait_for_refresh(realm::DB::version_type version, RLMAsyncRefreshCompletion completion) { + _refreshHandlers.emplace_back(version, completion); + } + +private: + // This is owned by the realm, so it needs to not retain the realm + __weak RLMRealm *const _realm; + std::vector _beforeNotify; + std::vector> _refreshHandlers; +}; +} // anonymous namespace + +std::unique_ptr RLMCreateBindingContext(__unsafe_unretained RLMRealm *const realm) { + return std::unique_ptr(new RLMNotificationHelper(realm)); +} + +void RLMAddBeforeNotifyBlock(RLMRealm *realm, dispatch_block_t block) { + static_cast(realm->_realm->m_binding_context.get())->add_before_notify_block(block); +} + +@implementation RLMPinnedRealm { + realm::TransactionRef _pin; +} + +- (instancetype)initWithRealm:(RLMRealm *)realm { + if (self = [super init]) { + _pin = realm->_realm->duplicate(); + _configuration = realm.configuration; + } + return self; +} + +- (void)unpin { + _pin.reset(); +} +@end + +RLMAsyncRefreshTask *RLMRealmRefreshAsync(RLMRealm *rlmRealm) { + auto& realm = *rlmRealm->_realm; + if (realm.is_frozen() || realm.config().immutable()) { + return nil; + } + + // Refresh is a no-op if the Realm isn't currently in a read transaction + // or is up-to-date + auto latest = realm.latest_snapshot_version(); + auto current = realm.current_transaction_version(); + if (!latest || !current || current->version == *latest) + return nil; + + // If autorefresh is disabled, we may have already been notified of a new + // version and simply not advanced to it. + advance_to_ready(realm); + + // This may have advanced to the latest version in which case there's + // nothing left to do + current = realm.current_transaction_version(); + if (current && current->version >= *latest) + return [RLMAsyncRefreshTask completedRefresh]; + auto refresh = [[RLMAsyncRefreshTask alloc] init]; + + // Register the continuation to be called once the new version is ready + auto& context = static_cast(*realm.m_binding_context); + context.wait_for_refresh(*latest, ^(bool didRefresh) { [refresh complete:didRefresh]; }); + return refresh; +} + +void RLMRunAsyncNotifiers(NSString *path) { + realm::_impl::RealmCoordinator::get_existing_coordinator(path.UTF8String)->on_change(); +} diff --git a/Pods/Realm/Realm/RLMResults.mm b/Pods/Realm/Realm/RLMResults.mm new file mode 100644 index 0000000..7df0958 --- /dev/null +++ b/Pods/Realm/Realm/RLMResults.mm @@ -0,0 +1,594 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMResults_Private.hpp" + +#import "RLMAccessor.hpp" +#import "RLMArray_Private.hpp" +#import "RLMCollection_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSectionedResults_Private.hpp" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +#import + +using namespace realm; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincomplete-implementation" +@implementation RLMNotificationToken +- (bool)invalidate { + return false; +} +@end +#pragma clang diagnostic pop + +@interface RLMResults () +@end + +// +// RLMResults implementation +// +@implementation RLMResults { + RLMRealm *_realm; + RLMClassInfo *_info; +} + +- (instancetype)initPrivate { + self = [super init]; + return self; +} + +- (instancetype)initWithResults:(Results)results { + if (self = [super init]) { + _results = std::move(results); + } + return self; +} + +static void assertKeyPathIsNotNested(NSString *keyPath) { + if ([keyPath rangeOfString:@"."].location != NSNotFound) { + @throw RLMException(@"Nested key paths are not supported yet for KVC collection operators."); + } +} + +void RLMThrowCollectionException(NSString *collectionName) { + try { + throw; + } + catch (realm::WrongTransactionState const&) { + @throw RLMException(@"Cannot modify %@ outside of a write transaction.", collectionName); + } + catch (realm::OutOfBounds const& e) { + @throw RLMException(@"Index %zu is out of bounds (must be less than %zu).", + e.index, e.size); + } + catch (realm::Exception const& e) { + @throw RLMException(e); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +template +__attribute__((always_inline)) +static auto translateErrors(Function&& f) { + return translateCollectionError(static_cast(f), @"Results"); +} + +- (instancetype)initWithObjectInfo:(RLMClassInfo&)info + results:(realm::Results&&)results { + if (self = [super init]) { + _results = std::move(results); + _realm = info.realm; + _info = &info; + } + return self; +} + ++ (instancetype)resultsWithObjectInfo:(RLMClassInfo&)info + results:(realm::Results&&)results { + return [[self alloc] initWithObjectInfo:info results:std::move(results)]; +} + ++ (instancetype)emptyDetachedResults { + return [[self alloc] initPrivate]; +} + +- (instancetype)subresultsWithResults:(realm::Results)results { + return [self.class resultsWithObjectInfo:*_info results:std::move(results)]; +} + +static inline void RLMResultsValidateInWriteTransaction(__unsafe_unretained RLMResults *const ar) { + ar->_realm->_realm->verify_thread(); + ar->_realm->_realm->verify_in_write(); +} + +- (BOOL)isInvalidated { + return translateErrors([&] { return !_results.is_valid(); }); +} + +- (NSUInteger)count { + return translateErrors([&] { return _results.size(); }); +} + +- (RLMPropertyType)type { + return translateErrors([&] { + return static_cast(_results.get_type() & ~realm::PropertyType::Nullable); + }); +} + +- (BOOL)isOptional { + return translateErrors([&] { + return is_nullable(_results.get_type()); + }); +} + +- (NSString *)objectClassName { + return translateErrors([&] { + if (_info && _results.get_type() == realm::PropertyType::Object) { + return _info->rlmObjectSchema.className; + } + return (NSString *)nil; + }); +} + +- (RLMClassInfo *)objectInfo { + return _info; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + if (!_info) { + return 0; + } + if (state->state == 0) { + translateErrors([&] { + _results.evaluate_query_if_needed(); + }); + } + return RLMFastEnumerate(state, len, self); +} + +- (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + NSUInteger index = [self indexOfObjectWhere:predicateFormat args:args]; + va_end(args); + return index; +} + +- (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat args:(va_list)args { + return [self indexOfObjectWithPredicate:[NSPredicate predicateWithFormat:predicateFormat + arguments:args]]; +} + +- (NSUInteger)indexOfObjectWithPredicate:(NSPredicate *)predicate { + if (_results.get_mode() == Results::Mode::Empty) { + return NSNotFound; + } + + return translateErrors([&] { + if (_results.get_type() != realm::PropertyType::Object) { + @throw RLMException(@"Querying is currently only implemented for arrays of Realm Objects"); + } + return RLMConvertNotFound(_results.index_of(RLMPredicateToQuery(predicate, _info->rlmObjectSchema, _realm.schema, _realm.group))); + }); +} + +- (id)objectAtIndex:(NSUInteger)index { + RLMAccessorContext ctx(*_info); + return translateErrors([&] { + return _results.get(ctx, index); + }); +} + +- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + if (!_info) { + return nil; + } + size_t c = self.count; + NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:indexes.count]; + NSUInteger i = [indexes firstIndex]; + RLMAccessorContext context(*_info); + while (i != NSNotFound) { + if (i >= 0 && i < c) { + [result addObject:_results.get(context, i)]; + } else { + return nil; + } + i = [indexes indexGreaterThanIndex:i]; + } + return result; +} + +- (id)firstObject { + if (!_info) { + return nil; + } + RLMAccessorContext ctx(*_info); + return translateErrors([&] { + return _results.first(ctx); + }); +} + +- (id)lastObject { + if (!_info) { + return nil; + } + RLMAccessorContext ctx(*_info); + return translateErrors([&] { + return _results.last(ctx); + }); +} + +- (NSUInteger)indexOfObject:(id)object { + if (!_info || !object) { + return NSNotFound; + } + if (RLMObjectBase *obj = RLMDynamicCast(object)) { + // Unmanaged objects are considered not equal to all managed objects + if (!obj->_realm && !obj.invalidated) { + return NSNotFound; + } + } + RLMAccessorContext ctx(*_info); + return translateErrors([&] { + return RLMConvertNotFound(_results.index_of(ctx, object)); + }); +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath characterAtIndex:0] != '@') { + return [super valueForKeyPath:keyPath]; + } + if ([keyPath isEqualToString:@"@count"]) { + return @(self.count); + } + + NSRange operatorRange = [keyPath rangeOfString:@"." options:NSLiteralSearch]; + NSUInteger keyPathLength = keyPath.length; + NSUInteger separatorIndex = operatorRange.location != NSNotFound ? operatorRange.location : keyPathLength; + NSString *operatorName = [keyPath substringWithRange:NSMakeRange(1, separatorIndex - 1)]; + SEL opSelector = NSSelectorFromString([NSString stringWithFormat:@"_%@ForKeyPath:", operatorName]); + if (![self respondsToSelector:opSelector]) { + @throw RLMException(@"Unsupported KVC collection operator found in key path '%@'", keyPath); + } + if (separatorIndex >= keyPathLength - 1) { + @throw RLMException(@"Missing key path for KVC collection operator %@ in key path '%@'", + operatorName, keyPath); + } + NSString *operatorKeyPath = [keyPath substringFromIndex:separatorIndex + 1]; + return ((id(*)(id, SEL, id))objc_msgSend)(self, opSelector, operatorKeyPath); +} + +- (id)valueForKey:(NSString *)key { + if (!_info) { + return @[]; + } + return translateErrors([&] { + return RLMCollectionValueForKey(_results, key, *_info); + }); +} + +- (void)setValue:(id)value forKey:(NSString *)key { + translateErrors([&] { RLMResultsValidateInWriteTransaction(self); }); + RLMCollectionSetValueForKey(self, key, value); +} + +- (NSNumber *)_aggregateForKeyPath:(NSString *)keyPath + method:(std::optional (Results::*)(ColKey))method + methodName:(NSString *)methodName returnNilForEmpty:(BOOL)returnNilForEmpty { + assertKeyPathIsNotNested(keyPath); + return [self aggregate:keyPath method:method returnNilForEmpty:returnNilForEmpty]; +} + +- (NSNumber *)_minForKeyPath:(NSString *)keyPath { + return [self _aggregateForKeyPath:keyPath method:&Results::min methodName:@"@min" returnNilForEmpty:YES]; +} + +- (NSNumber *)_maxForKeyPath:(NSString *)keyPath { + return [self _aggregateForKeyPath:keyPath method:&Results::max methodName:@"@max" returnNilForEmpty:YES]; +} + +- (NSNumber *)_sumForKeyPath:(NSString *)keyPath { + return [self _aggregateForKeyPath:keyPath method:&Results::sum methodName:@"@sum" returnNilForEmpty:NO]; +} + +- (NSNumber *)_avgForKeyPath:(NSString *)keyPath { + assertKeyPathIsNotNested(keyPath); + return [self averageOfProperty:keyPath]; +} + +- (NSArray *)_unionOfObjectsForKeyPath:(NSString *)keyPath { + assertKeyPathIsNotNested(keyPath); + return translateErrors([&] { + return RLMCollectionValueForKey(_results, keyPath, *_info); + }); +} + +- (NSArray *)_distinctUnionOfObjectsForKeyPath:(NSString *)keyPath { + return [NSSet setWithArray:[self _unionOfObjectsForKeyPath:keyPath]].allObjects; +} + +- (NSArray *)_unionOfArraysForKeyPath:(NSString *)keyPath { + assertKeyPathIsNotNested(keyPath); + if ([keyPath isEqualToString:@"self"]) { + @throw RLMException(@"self is not a valid key-path for a KVC array collection operator as 'unionOfArrays'."); + } + + return translateErrors([&] { + NSMutableArray *flatArray = [NSMutableArray new]; + for (id array in RLMCollectionValueForKey(_results, keyPath, *_info)) { + for (id value in array) { + [flatArray addObject:value]; + } + } + return flatArray; + }); +} + +- (NSArray *)_distinctUnionOfArraysForKeyPath:(__unused NSString *)keyPath { + return [NSSet setWithArray:[self _unionOfArraysForKeyPath:keyPath]].allObjects; +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsWhere:predicateFormat args:args]; + va_end(args); + return results; +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args { + return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + return translateErrors([&] { + if (_results.get_mode() == Results::Mode::Empty) { + return self; + } + if (_results.get_type() != realm::PropertyType::Object) { + @throw RLMException(@"Querying is currently only implemented for arrays of Realm Objects"); + } + auto query = RLMPredicateToQuery(predicate, _info->rlmObjectSchema, _realm.schema, _realm.group); + return [self subresultsWithResults:_results.filter(std::move(query))]; + }); +} + +- (RLMResults *)sortedResultsUsingKeyPath:(NSString *)keyPath ascending:(BOOL)ascending { + return [self sortedResultsUsingDescriptors:@[[RLMSortDescriptor sortDescriptorWithKeyPath:keyPath ascending:ascending]]]; +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + if (properties.count == 0) { + return self; + } + return translateErrors([&] { + if (_results.get_mode() == Results::Mode::Empty) { + return self; + } + return [self subresultsWithResults:_results.sort(RLMSortDescriptorsToKeypathArray(properties))]; + }); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + for (NSString *keyPath in keyPaths) { + if ([keyPath rangeOfString:@"@"].location != NSNotFound) { + @throw RLMException(@"Cannot distinct on keypath '%@': KVC collection operators are not supported.", keyPath); + } + } + return translateErrors([&] { + if (_results.get_mode() == Results::Mode::Empty) { + return self; + } + + std::vector keyPathsVector; + for (NSString *keyPath in keyPaths) { + keyPathsVector.push_back(keyPath.UTF8String); + } + + return [self subresultsWithResults:_results.distinct(keyPathsVector)]; + }); +} + +- (id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +- (id)aggregate:(NSString *)property + method:(std::optional (Results::*)(ColKey))method +returnNilForEmpty:(BOOL)returnNilForEmpty { + if (_results.get_mode() == Results::Mode::Empty) { + return returnNilForEmpty ? nil : @0; + } + ColKey column; + if (self.type == RLMPropertyTypeObject || ![property isEqualToString:@"self"]) { + column = _info->tableColumn(property); + } + + auto value = translateErrors([&] { return (_results.*method)(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)minOfProperty:(NSString *)property { + return [self aggregate:property method:&Results::min returnNilForEmpty:YES]; +} + +- (id)maxOfProperty:(NSString *)property { + return [self aggregate:property method:&Results::max returnNilForEmpty:YES]; +} + +- (id)sumOfProperty:(NSString *)property { + return [self aggregate:property method:&Results::sum returnNilForEmpty:NO]; +} + +- (id)averageOfProperty:(NSString *)property { + return [self aggregate:property method:&Results::average returnNilForEmpty:YES]; +} + +- (RLMSectionedResults *)sectionedResultsSortedUsingKeyPath:(NSString *)keyPath + ascending:(BOOL)ascending + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + return [[RLMSectionedResults alloc] initWithResults:[self sortedResultsUsingKeyPath:keyPath ascending:ascending] + keyBlock:keyBlock]; +} + +- (RLMSectionedResults *)sectionedResultsUsingSortDescriptors:(NSArray *)sortDescriptors + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + return [[RLMSectionedResults alloc] initWithResults:[self sortedResultsUsingDescriptors:sortDescriptors] + keyBlock:keyBlock]; +} + +- (void)deleteObjectsFromRealm { + if (self.type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMResults<%@>: only RLMObjects can be deleted.", + RLMTypeToString(self.type)); + } + return translateErrors([&] { + if (_results.get_mode() == Results::Mode::Table) { + RLMResultsValidateInWriteTransaction(self); + RLMClearTable(*_info); + } + else { + RLMObservationTracker tracker(_realm, true); + _results.clear(); + } + }); +} + +- (NSString *)description { + return RLMDescriptionWithMaxDepth(@"RLMResults", self, RLMDescriptionMaxDepth); +} + +- (realm::TableView)tableView { + return translateErrors([&] { return _results.get_tableview(); }); +} + +- (RLMFastEnumerator *)fastEnumerator { + return translateErrors([&] { + return [[RLMFastEnumerator alloc] initWithResults:_results + collection:self + classInfo:*_info]; + }); +} + +- (RLMResults *)snapshot { + return translateErrors([&] { + return [self subresultsWithResults:_results.snapshot()]; + }); +} + +- (BOOL)isFrozen { + return _realm.frozen; +} + +- (instancetype)resolveInRealm:(RLMRealm *)realm { + return translateErrors([&] { + return [self.class resultsWithObjectInfo:_info->resolve(realm) + results:_results.freeze(realm->_realm)]; + }); +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + return [self resolveInRealm:_realm.freeze]; +} + +- (instancetype)thaw { + if (!self.frozen) { + return self; + } + return [self resolveInRealm:_realm.thaw]; +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMCollectionChange *, NSError *))block { + return RLMAddNotificationBlock(self, block, nil, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMCollectionChange *, NSError *))block queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMCollectionChange *, NSError *))block keyPaths:(NSArray *)keyPaths { + return RLMAddNotificationBlock(self, block, keyPaths, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMCollectionChange *, NSError *))block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, keyPaths, queue); +} +#pragma clang diagnostic pop + +- (realm::NotificationToken)addNotificationCallback:(id)block +keyPaths:(std::optional>>>&&)keyPaths { + return _results.add_notification_callback(RLMWrapCollectionChangeCallback(block, self, true), std::move(keyPaths)); +} + +- (BOOL)isAttached { + return !!_realm; +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _results; +} + +- (id)objectiveCMetadata { + return nil; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(__unused id)metadata + realm:(RLMRealm *)realm { + auto results = reference.resolve(realm->_realm); + return [RLMResults resultsWithObjectInfo:realm->_info[RLMStringDataToNSString(results.get_object_type())] + results:std::move(results)]; +} + +@end + +@implementation RLMLinkingObjects +- (NSString *)description { + return RLMDescriptionWithMaxDepth(@"RLMLinkingObjects", self, RLMDescriptionMaxDepth); +} +@end diff --git a/Pods/Realm/Realm/RLMScheduler.mm b/Pods/Realm/Realm/RLMScheduler.mm new file mode 100644 index 0000000..75fd556 --- /dev/null +++ b/Pods/Realm/Realm/RLMScheduler.mm @@ -0,0 +1,217 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2023 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMScheduler.h" + +#import "RLMUtil.hpp" + +#include + +@interface RLMMainRunLoopScheduler : RLMScheduler +@end + +RLM_HIDDEN +@implementation RLMMainRunLoopScheduler +- (std::shared_ptr)osScheduler { + return realm::util::Scheduler::make_runloop(CFRunLoopGetMain()); +} + +- (void *)cacheKey { + // The main thread and main queue share a cache key of `std::numeric_limits::max()` + // so that they give the same instance. Other Realms are keyed on either the thread or the queue. + // Note that despite being a void* the cache key is not actually a pointer; + // this is just an artifact of NSMapTable's strange API. + return reinterpret_cast(std::numeric_limits::max()); +} + +// We can't access MainActor.shared directly from obj-c and need to set it from +// Swift. The locking here is _almost_ unnecessary as this is set from a static +// initializer before the value can ever be read, but mixed use of the obj-c and +// Swift APIs could potentially race on the read. +static auto& g_mainActorLock = *new RLMUnfairMutex; +static id g_mainActor; +void RLMSetMainActor(id actor) { + std::lock_guard lock(g_mainActorLock); + g_mainActor = actor; +} +- (id)actor { + std::lock_guard lock(g_mainActorLock); + return g_mainActor; +} + +- (void)invoke:(dispatch_block_t)block { + dispatch_async(dispatch_get_main_queue(), block); +} +@end + +@interface RLMDispatchQueueScheduler : RLMScheduler +@end + +RLM_HIDDEN +@implementation RLMDispatchQueueScheduler { + dispatch_queue_t _queue; +} + +- (instancetype)initWithQueue:(dispatch_queue_t)queue { + if (self = [super init]) { + _queue = queue; + } + return self; +} + +- (void)invoke:(dispatch_block_t)block { + dispatch_async(_queue, block); +} + +- (std::shared_ptr)osScheduler { + if (_queue == dispatch_get_main_queue()) { + return RLMScheduler.mainRunLoop.osScheduler; + } + return realm::util::Scheduler::make_dispatch((__bridge void *)_queue); +} + +- (void *)cacheKey { + if (_queue == dispatch_get_main_queue()) { + return RLMScheduler.mainRunLoop.cacheKey; + } + return (__bridge void *)_queue; +} +@end + +namespace { +class ActorScheduler final : public realm::util::Scheduler { +public: + ActorScheduler(void (^invoke)(dispatch_block_t), dispatch_block_t verify) + : _invoke(invoke) , _verify(verify) {} + + void invoke(realm::util::UniqueFunction&& fn) override { + auto ptr = fn.release(); + _invoke(^{ + realm::util::UniqueFunction fn(ptr); + fn(); + }); + } + + // This currently isn't actually implementable, but fortunately is only used + // to report errors when we aren't on the thread, so triggering the actor + // data race detection is good enough. + bool is_on_thread() const noexcept override { + _verify(); + return true; + } + + // This is used for OS Realm caching, which we don't use (as we have our own cache) + bool is_same_as(const Scheduler *) const noexcept override { + REALM_UNREACHABLE(); + } + + // Actor isolated Realms can always invoke blocks + bool can_invoke() const noexcept override { + return true; + } + +private: + void (^_invoke)(dispatch_block_t); + dispatch_block_t _verify; +}; +} + +@interface RLMActorScheduler : RLMScheduler +@end + +RLM_HIDDEN +@implementation RLMActorScheduler { + id _actor; + void (^_invoke)(dispatch_block_t); + void (^_verify)(); +} + +- (instancetype)initWithActor:(id)actor invoke:(void (^)(dispatch_block_t))invoke verify:(void (^)())verify { + if (self = [super init]) { + _actor = actor; + _invoke = invoke; + _verify = verify; + } + return self; +} + +- (void)invoke:(dispatch_block_t)block { + _invoke(block); +} + +- (std::shared_ptr)osScheduler { + return std::make_shared(_invoke, _verify); +} + +- (void *)cacheKey { + return (__bridge void *)_actor; +} + +- (id)actor { + return _actor; +} +@end + +@implementation RLMScheduler ++ (RLMScheduler *)currentRunLoop { + if (pthread_main_np()) { + return RLMScheduler.mainRunLoop; + } + + static RLMScheduler *currentRunLoopScheduler = [[RLMScheduler alloc] init]; + return currentRunLoopScheduler; +} + ++ (RLMScheduler *)mainRunLoop { + static RLMScheduler *mainRunLoopScheduler = [[RLMMainRunLoopScheduler alloc] init]; + return mainRunLoopScheduler; +} + ++ (RLMScheduler *)dispatchQueue:(dispatch_queue_t)queue { + if (queue) { + return [[RLMDispatchQueueScheduler alloc] initWithQueue:queue]; + } + return RLMScheduler.currentRunLoop; +} + ++ (RLMScheduler *)actor:(id)actor invoke:(void (^)(dispatch_block_t))invoke verify:(void (^)())verify { + auto mainRunLoopScheduler = RLMScheduler.mainRunLoop; + if (actor == mainRunLoopScheduler.actor) { + return mainRunLoopScheduler; + } + return [[RLMActorScheduler alloc] initWithActor:actor invoke:invoke verify:verify]; +} + +- (void)invoke:(dispatch_block_t)block { + // Currently not used or needed for run loops + REALM_UNREACHABLE(); +} + +- (std::shared_ptr)osScheduler { + // For normal thread-confined Realms we let object store create the scheduler + return nullptr; +} + +- (void *)cacheKey { + return pthread_self(); +} + +- (id)actor { + return nil; +} +@end diff --git a/Pods/Realm/Realm/RLMSchema.mm b/Pods/Realm/Realm/RLMSchema.mm new file mode 100644 index 0000000..aeb72f9 --- /dev/null +++ b/Pods/Realm/Realm/RLMSchema.mm @@ -0,0 +1,415 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMSchema_Private.hpp" + +#import "RLMAccessor.h" +#import "RLMObjectBase_Private.h" +#import "RLMObject_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMProperty_Private.h" +#import "RLMRealm_Private.hpp" +#import "RLMSwiftSupport.h" +#import "RLMUtil.hpp" + +#import +#import +#import +#import +#import + +#import +#import + +using namespace realm; + +const uint64_t RLMNotVersioned = realm::ObjectStore::NotVersioned; + +// RLMSchema private properties +@interface RLMSchema () +@property (nonatomic, readwrite) NSMutableDictionary *objectSchemaByName; +@end + +// Private RLMSchema subclass that skips class registration on lookup +@interface RLMPrivateSchema : RLMSchema +@end +@implementation RLMPrivateSchema +- (RLMObjectSchema *)schemaForClassName:(NSString *)className { + return self.objectSchemaByName[className]; +} + +- (RLMObjectSchema *)objectForKeyedSubscript:(__unsafe_unretained NSString *const)className { + return [self schemaForClassName:className]; +} +@end + +static RLMSchema *s_sharedSchema = [[RLMSchema alloc] init]; +static NSMutableDictionary *s_localNameToClass = [[NSMutableDictionary alloc] init]; +static RLMSchema *s_privateSharedSchema = [[RLMPrivateSchema alloc] init]; + +static enum class SharedSchemaState { + Uninitialized, + Initializing, + Initialized +} s_sharedSchemaState = SharedSchemaState::Uninitialized; + +@implementation RLMSchema { + NSArray *_objectSchema; + realm::Schema _objectStoreSchema; +} + +static void createAccessors(RLMObjectSchema *objectSchema) { + constexpr const size_t bufferSize + = sizeof("RLM:Managed ") // includes spot for null terminator + + std::numeric_limits::digits10 + + realm::Group::max_table_name_length; + + char className[bufferSize] = "RLM:Managed "; + char *const start = className + strlen(className); + + static unsigned long long count = 0; + snprintf(start, bufferSize - strlen(className), + "%llu %s", count++, objectSchema.className.UTF8String); + objectSchema.accessorClass = RLMManagedAccessorClassForObjectClass(objectSchema.objectClass, objectSchema, className); + objectSchema.unmanagedClass = RLMUnmanagedAccessorClassForObjectClass(objectSchema.objectClass, objectSchema); +} + +void RLMSchemaEnsureAccessorsCreated(RLMSchema *schema) { + for (RLMObjectSchema *objectSchema in schema.objectSchema) { + if (objectSchema.accessorClass == objectSchema.objectClass) { + // Locking inside the loop to optimize for the common case at + // the expense of worse perf in the rare scenario where this is + // actually needed. + @synchronized(s_localNameToClass) { + createAccessors(objectSchema); + } + } + } +} + +// Caller must @synchronize on s_localNameToClass +static RLMObjectSchema *registerClass(Class cls) { + if (RLMObjectSchema *schema = s_privateSharedSchema[[cls className]]) { + return schema; + } + + auto prevState = s_sharedSchemaState; + s_sharedSchemaState = SharedSchemaState::Initializing; + RLMObjectSchema *schema; + { + util::ScopeExit cleanup([&]() noexcept { + s_sharedSchemaState = prevState; + }); + schema = [RLMObjectSchema schemaForObjectClass:cls]; + } + + createAccessors(schema); + // override sharedSchema class methods for performance + RLMReplaceSharedSchemaMethod(cls, schema); + + s_privateSharedSchema.objectSchemaByName[schema.className] = schema; + if ([cls shouldIncludeInDefaultSchema] && prevState != SharedSchemaState::Initialized) { + s_sharedSchema.objectSchemaByName[schema.className] = schema; + } + + return schema; +} + +// Caller must @synchronize on s_localNameToClass +static void RLMRegisterClassLocalNames(Class *classes, NSUInteger count) { + for (NSUInteger i = 0; i < count; i++) { + Class cls = classes[i]; + if (!RLMIsObjectSubclass(cls)) { + continue; + } + if ([cls _realmIgnoreClass]) { + continue; + } + + NSString *className = NSStringFromClass(cls); + if ([className hasPrefix:@"RLM:"] || [className hasPrefix:@"NSKVONotifying"]) { + continue; + } + + if ([RLMSwiftSupport isSwiftClassName:className]) { + className = [RLMSwiftSupport demangleClassName:className]; + } + // NSStringFromClass demangles the names for top-level Swift classes + // but not for nested classes. _T indicates it's a Swift symbol, t + // indicates it's a type, and C indicates it's a class. + else if ([className hasPrefix:@"_TtC"]) { + @throw RLMException(@"Object subclass '%@' must explicitly set the class's objective-c name with @objc(ClassName) because it is not a top-level public class.", className); + } + + if (Class existingClass = s_localNameToClass[className]) { + if (existingClass != cls) { + @throw RLMException(@"RLMObject subclasses with the same name cannot be included twice in the same target. " + @"Please make sure '%@' is only linked once to your current target.", className); + } + continue; + } + + s_localNameToClass[className] = cls; + RLMReplaceClassNameMethod(cls, className); + } +} + +- (instancetype)init { + self = [super init]; + if (self) { + _objectSchemaByName = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (NSArray *)objectSchema { + if (!_objectSchema) { + _objectSchema = [_objectSchemaByName allValues]; + } + return _objectSchema; +} + +- (void)setObjectSchema:(NSArray *)objectSchema { + _objectSchema = objectSchema; + _objectSchemaByName = [NSMutableDictionary dictionaryWithCapacity:objectSchema.count]; + for (RLMObjectSchema *object in objectSchema) { + [_objectSchemaByName setObject:object forKey:object.className]; + } +} + +- (RLMObjectSchema *)schemaForClassName:(NSString *)className { + if (RLMObjectSchema *schema = _objectSchemaByName[className]) { + return schema; // fast path for already-initialized schemas + } else if (Class cls = [RLMSchema classForString:className]) { + [cls sharedSchema]; // initialize the schema + return _objectSchemaByName[className]; // try again + } else { + return nil; + } +} + +- (RLMObjectSchema *)objectForKeyedSubscript:(__unsafe_unretained NSString *const)className { + RLMObjectSchema *schema = [self schemaForClassName:className]; + if (!schema) { + @throw RLMException(@"Object type '%@' not managed by the Realm", className); + } + return schema; +} + ++ (instancetype)schemaWithObjectClasses:(NSArray *)classes { + NSUInteger count = classes.count; + auto classArray = std::make_unique<__unsafe_unretained Class[]>(count); + [classes getObjects:classArray.get() range:NSMakeRange(0, count)]; + + RLMSchema *schema = [[self alloc] init]; + @synchronized(s_localNameToClass) { + RLMRegisterClassLocalNames(classArray.get(), count); + + schema->_objectSchemaByName = [NSMutableDictionary dictionaryWithCapacity:count]; + for (Class cls in classes) { + if (!RLMIsObjectSubclass(cls)) { + @throw RLMException(@"Can't add non-Object type '%@' to a schema.", cls); + } + schema->_objectSchemaByName[[cls className]] = registerClass(cls); + } + } + + NSMutableArray *errors = [NSMutableArray new]; + // Verify that all of the targets of links are included in the class list + [schema->_objectSchemaByName enumerateKeysAndObjectsUsingBlock:^(id, RLMObjectSchema *objectSchema, BOOL *) { + for (RLMProperty *prop in objectSchema.properties) { + if (prop.type != RLMPropertyTypeObject) { + continue; + } + if (!schema->_objectSchemaByName[prop.objectClassName]) { + [errors addObject:[NSString stringWithFormat:@"- '%@.%@' links to class '%@', which is missing from the list of classes managed by the Realm", objectSchema.className, prop.name, prop.objectClassName]]; + } + } + }]; + if (errors.count) { + @throw RLMException(@"Invalid class subset list:\n%@", [errors componentsJoinedByString:@"\n"]); + } + + return schema; +} + ++ (RLMObjectSchema *)sharedSchemaForClass:(Class)cls { + @synchronized(s_localNameToClass) { + // We create instances of Swift objects during schema init, and they + // obviously need to not also try to initialize the schema + if (s_sharedSchemaState == SharedSchemaState::Initializing) { + return nil; + } + // Don't register the base classes in the schema even if someone calls + // sharedSchema on them directly + if (cls == [RLMObjectBase class] || class_getSuperclass(cls) == [RLMObjectBase class]) { + return nil; + } + + RLMRegisterClassLocalNames(&cls, 1); + RLMObjectSchema *objectSchema = registerClass(cls); + [cls initializeLinkedObjectSchemas]; + return objectSchema; + } +} + ++ (instancetype)partialSharedSchema { + return s_sharedSchema; +} + ++ (instancetype)partialPrivateSharedSchema { + return s_privateSharedSchema; +} + +// schema based on runtime objects ++ (instancetype)sharedSchema { + @synchronized(s_localNameToClass) { + // We replace this method with one which just returns s_sharedSchema + // once initialization is complete, but we still need to check if it's + // already complete because it may have been done by another thread + // while we were waiting for the lock + if (s_sharedSchemaState == SharedSchemaState::Initialized) { + return s_sharedSchema; + } + + if (s_sharedSchemaState == SharedSchemaState::Initializing) { + @throw RLMException(@"Illegal recursive call of +[%@ %@]. Note: Properties of Swift `Object` classes must not be prepopulated with queried results from a Realm.", self, NSStringFromSelector(_cmd)); + } + + s_sharedSchemaState = SharedSchemaState::Initializing; + try { + // Make sure we've discovered all classes + { + unsigned int numClasses; + using malloc_ptr = std::unique_ptr<__unsafe_unretained Class[], decltype(&free)>; + malloc_ptr classes(objc_copyClassList(&numClasses), &free); + RLMRegisterClassLocalNames(classes.get(), numClasses); + } + + [s_localNameToClass enumerateKeysAndObjectsUsingBlock:^(NSString *, Class cls, BOOL *) { + registerClass(cls); + }]; + } + catch (...) { + s_sharedSchemaState = SharedSchemaState::Uninitialized; + throw; + } + + // Replace this method with one that doesn't need to acquire a lock + Class metaClass = objc_getMetaClass(class_getName(self)); + IMP imp = imp_implementationWithBlock(^{ return s_sharedSchema; }); + class_replaceMethod(metaClass, @selector(sharedSchema), imp, "@@:"); + + s_sharedSchemaState = SharedSchemaState::Initialized; + } + + return s_sharedSchema; +} + +// schema based on tables in a realm ++ (instancetype)dynamicSchemaFromObjectStoreSchema:(Schema const&)objectStoreSchema { + // cache descriptors for all subclasses of RLMObject + NSMutableArray *schemaArray = [NSMutableArray arrayWithCapacity:objectStoreSchema.size()]; + for (auto &objectSchema : objectStoreSchema) { + RLMObjectSchema *schema = [RLMObjectSchema objectSchemaForObjectStoreSchema:objectSchema]; + [schemaArray addObject:schema]; + } + + // set class array and mapping + RLMSchema *schema = [RLMSchema new]; + schema.objectSchema = schemaArray; + return schema; +} + ++ (Class)classForString:(NSString *)className { + if (Class cls = s_localNameToClass[className]) { + return cls; + } + + if (Class cls = NSClassFromString(className)) { + return RLMIsObjectSubclass(cls) ? cls : nil; + } + + // className might be the local name of a Swift class we haven't registered + // yet, so scan them all then recheck + { + unsigned int numClasses; + std::unique_ptr<__unsafe_unretained Class[], decltype(&free)> classes(objc_copyClassList(&numClasses), &free); + RLMRegisterClassLocalNames(classes.get(), numClasses); + } + + return s_localNameToClass[className]; +} + +- (id)copyWithZone:(NSZone *)zone { + RLMSchema *schema = [[RLMSchema allocWithZone:zone] init]; + schema->_objectSchemaByName = [[NSMutableDictionary allocWithZone:zone] + initWithDictionary:_objectSchemaByName copyItems:YES]; + return schema; +} + +- (BOOL)isEqualToSchema:(RLMSchema *)schema { + if (_objectSchemaByName.count != schema->_objectSchemaByName.count) { + return NO; + } + __block BOOL matches = YES; + [_objectSchemaByName enumerateKeysAndObjectsUsingBlock:^(NSString *name, RLMObjectSchema *objectSchema, BOOL *stop) { + if (![schema->_objectSchemaByName[name] isEqualToObjectSchema:objectSchema]) { + *stop = YES; + matches = NO; + } + }]; + return matches; +} + +- (NSString *)description { + NSMutableString *objectSchemaString = [NSMutableString string]; + NSArray *sort = @[[NSSortDescriptor sortDescriptorWithKey:@"className" ascending:YES]]; + for (RLMObjectSchema *objectSchema in [self.objectSchema sortedArrayUsingDescriptors:sort]) { + [objectSchemaString appendFormat:@"\t%@\n", + [objectSchema.description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]]; + } + return [NSString stringWithFormat:@"Schema {\n%@}", objectSchemaString]; +} + +- (Schema)objectStoreCopy { + if (_objectStoreSchema.size() == 0) { + std::vector schema; + schema.reserve(_objectSchemaByName.count); + [_objectSchemaByName enumerateKeysAndObjectsUsingBlock:[&](NSString *, RLMObjectSchema *objectSchema, BOOL *) { + schema.push_back([objectSchema objectStoreCopy:self]); + }]; + + // Having both obj-c and Swift classes for the same tables results in + // duplicate ObjectSchemas that we need to filter out + std::sort(begin(schema), end(schema), [](auto&& a, auto&& b) { return a.name < b.name; }); + schema.erase(std::unique(begin(schema), end(schema), [](auto&& a, auto&& b) { + if (a.name == b.name) { + // If we make _realmObjectName public this needs to be turned into an exception + REALM_ASSERT_DEBUG(a.persisted_properties == b.persisted_properties); + return true; + } + return false; + }), end(schema)); + + _objectStoreSchema = std::move(schema); + } + return _objectStoreSchema; +} + +@end diff --git a/Pods/Realm/Realm/RLMSectionedResults.mm b/Pods/Realm/Realm/RLMSectionedResults.mm new file mode 100644 index 0000000..df78ce8 --- /dev/null +++ b/Pods/Realm/Realm/RLMSectionedResults.mm @@ -0,0 +1,669 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMSectionedResults_Private.hpp" +#import "RLMAccessor.hpp" +#import "RLMCollection_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMResults.h" +#import "RLMResults_Private.hpp" +#import "RLMThreadSafeReference_Private.hpp" + +namespace { +struct CollectionCallbackWrapper { + void (^block)(id, RLMSectionedResultsChange *); + id collection; + bool ignoreChangesInInitialNotification = true; + + void operator()(realm::SectionedResultsChangeSet const& changes) { + if (ignoreChangesInInitialNotification) { + ignoreChangesInInitialNotification = false; + return block(collection, nil); + } + + block(collection, [[RLMSectionedResultsChange alloc] initWithChanges:changes]); + } +}; + +template +__attribute__((always_inline)) +auto translateErrors(Function&& f) { + return translateCollectionError(static_cast(f), @"SectionedResults"); +} +} // anonymous namespace + +@implementation RLMSectionedResultsChange { + realm::SectionedResultsChangeSet _indices; +} + +- (instancetype)initWithChanges:(realm::SectionedResultsChangeSet)indices { + self = [super init]; + if (self) { + _indices = std::move(indices); + } + return self; +} + +- (NSArray *)indexesFromVector:(std::vector const&)indexMap { + NSMutableArray *a = [NSMutableArray new]; + for (size_t i = 0; i < indexMap.size(); ++i) { + NSUInteger path[2] = {i, 0}; + for (auto index : indexMap[i].as_indexes()) { + path[1] = index; + [a addObject:[NSIndexPath indexPathWithIndexes:path length:2]]; + } + } + return a; +} + +- (NSArray *)insertions { + return [self indexesFromVector:_indices.insertions]; +} + +- (NSArray *)deletions { + return [self indexesFromVector:_indices.deletions]; +} + +- (NSArray *)modifications { + return [self indexesFromVector:_indices.modifications]; +} + +- (NSIndexSet *)sectionsToInsert { + NSMutableIndexSet *indices = [NSMutableIndexSet new]; + for (auto i : _indices.sections_to_insert.as_indexes()) { + [indices addIndex:i]; + } + return indices; +} + +- (NSIndexSet *)sectionsToRemove { + NSMutableIndexSet *indices = [NSMutableIndexSet new]; + for (auto i : _indices.sections_to_delete.as_indexes()) { + [indices addIndex:i]; + } + return indices; +} + +/// Returns the index paths of the deletion indices in the given section. +- (NSArray *)deletionsInSection:(NSUInteger)section { + return RLMToIndexPathArray(_indices.deletions[section], section); +} + +/// Returns the index paths of the insertion indices in the given section. +- (NSArray *)insertionsInSection:(NSUInteger)section { + return RLMToIndexPathArray(_indices.insertions[section], section); +} + +/// Returns the index paths of the modification indices in the given section. +- (NSArray *)modificationsInSection:(NSUInteger)section { + return RLMToIndexPathArray(_indices.modifications[section], section); +} + +static NSString *indexPathToString(NSArray *indexes) { + if (indexes.count == 0) { + return @"[]"; + } + return [NSString stringWithFormat:@"[\n\t%@\n\t]", [indexes componentsJoinedByString:@"\n\t\t"]]; +}; + +static NSString *indexSetToString(NSIndexSet *sections) { + if (sections.count == 0) { + return @"[]"; + } + return [NSString stringWithFormat:@"[\n\t%@\n\t]", sections]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@" {\n\tinsertions: %@,\n\tdeletions: %@,\n\tmodifications: %@,\n\tsectionsToInsert: %@,\n\tsectionsToRemove: %@\n}", + (__bridge void *)self, + indexPathToString(self.insertions), + indexPathToString(self.deletions), + indexPathToString(self.modifications), + indexSetToString(self.sectionsToInsert), indexSetToString(self.sectionsToRemove)]; +} + +@end + +struct SectionedResultsKeyProjection { + RLMClassInfo *_info; + RLMSectionedResultsKeyBlock _block; + + realm::Mixed operator()(realm::Mixed obj, realm::SharedRealm) { + RLMAccessorContext context(*_info); + id value = _block(context.box(obj)); + return context.unbox(value); + } +}; + +@interface RLMSectionedResultsEnumerator() { + // The buffer supplied by fast enumeration does not retain the objects given + // to it, but because we create objects on-demand and don't want them + // autoreleased (a table can have more rows than the device has memory for + // accessor objects) we need a thing to retain them. + id _strongBuffer[16]; + id _sectionedResult; +} +@end + +@implementation RLMSectionedResultsEnumerator + +- (instancetype)initWithSectionedResults:(RLMSectionedResults *)sectionedResults { + if (self = [super init]) { + _sectionedResult = [sectionedResults snapshot]; + return self; + } + return nil; +} + +- (instancetype)initWithResultsSection:(RLMSection *)resultsSection { + if (self = [super init]) { + _sectionedResult = resultsSection; + return self; + } + return nil; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + count:(NSUInteger)len { + NSUInteger batchCount = 0, count = [_sectionedResult count]; + for (NSUInteger index = state->state; index < count && batchCount < len; ++index) { + id sectionedResults = [_sectionedResult objectAtIndex:index]; + _strongBuffer[batchCount] = sectionedResults; + batchCount++; + } + + for (NSUInteger i = batchCount; i < len; ++i) { + _strongBuffer[i] = nil; + } + + if (batchCount == 0) { + // Release our data if we're done, as we're autoreleased and so may + // stick around for a while + if (_sectionedResult) { + _sectionedResult = nil; + } + } + + state->itemsPtr = (__unsafe_unretained id *)(void *)_strongBuffer; + state->state += batchCount; + state->mutationsPtr = state->extra+1; + + return batchCount; +} + +@end + +NSUInteger RLMFastEnumerate(NSFastEnumerationState *state, + NSUInteger len, + RLMSectionedResults *collection) { + __autoreleasing RLMSectionedResultsEnumerator *enumerator; + if (state->state == 0) { + enumerator = collection.fastEnumerator; + state->extra[0] = (long)enumerator; + state->extra[1] = collection.count; + } + else { + enumerator = (__bridge id)(void *)state->extra[0]; + } + + return [enumerator countByEnumeratingWithState:state count:len]; +} + +NSUInteger RLMFastEnumerate(NSFastEnumerationState *state, + NSUInteger len, + RLMSection *collection) { + __autoreleasing RLMSectionedResultsEnumerator *enumerator; + if (state->state == 0) { + enumerator = collection.fastEnumerator; + state->extra[0] = (long)enumerator; + state->extra[1] = collection.count; + } + else { + enumerator = (__bridge id)(void *)state->extra[0]; + } + + return [enumerator countByEnumeratingWithState:state count:len]; +} + +@interface RLMSectionedResults () +@end + +@implementation RLMSectionedResults { + @public + realm::SectionedResults _sectionedResults; + RLMSectionedResultsKeyBlock _keyBlock; + // We need to hold an instance to the parent + // `Results` so we can obtain a ThreadSafeReference + // for notifications. + realm::Results _results; + @private + RLMRealm *_realm; + RLMClassInfo *_info; +} + +- (instancetype)initWithResults:(realm::Results&&)results + realm:(RLMRealm *)realm + objectInfo:(RLMClassInfo&)objectInfo + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + if (self = [super init]) { + _info = &objectInfo; + _realm = realm; + _keyBlock = keyBlock; + _results = std::move(results); + _sectionedResults = _results.sectioned_results(SectionedResultsKeyProjection{_info, _keyBlock}); + } + return self; +} + +- (instancetype)initWithSectionedResults:(realm::SectionedResults&&)sectionedResults + objectInfo:(RLMClassInfo&)objectInfo + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock{ + if (self = [super init]) { + _info = &objectInfo; + _realm = _info->realm; + _sectionedResults = std::move(sectionedResults); + _keyBlock = keyBlock; + } + return self; +} + +- (instancetype)initWithResults:(RLMResults *)results + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + if (self = [super init]) { + _info = results.objectInfo; + _realm = results.realm; + _keyBlock = keyBlock; + _results = results->_results; + _sectionedResults = results->_results.sectioned_results(SectionedResultsKeyProjection{_info, _keyBlock}); + } + return self; +} + +- (NSArray *)allKeys { + return translateErrors([&] { + NSUInteger count = [self count]; + NSMutableArray *arr = [NSMutableArray arrayWithCapacity:count]; + for (NSUInteger i = 0; i < count; i++) { + [arr addObject:RLMMixedToObjc(_sectionedResults[i].key())]; + } + return arr; + }); +} + +- (RLMSectionedResultsEnumerator *)fastEnumerator { + return [[RLMSectionedResultsEnumerator alloc] initWithSectionedResults:self]; +} + +- (RLMRealm *)realm { + return _realm; +} + +- (NSUInteger)count { + return translateErrors([&] { + return _sectionedResults.size(); + }); +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + return RLMFastEnumerate(state, len, self); +} + +- (id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +- (id)objectAtIndex:(NSUInteger)index { + return [[RLMSection alloc] initWithResultsSection:_sectionedResults[index] + parent:self]; +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block { + return RLMAddNotificationBlock(self, block, nil, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block + keyPaths:(NSArray *)keyPaths { + return RLMAddNotificationBlock(self, block, keyPaths, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, keyPaths, queue); +} +#pragma clang diagnostic pop + +- (realm::NotificationToken)addNotificationCallback:(id)block +keyPaths:(std::optional>>>&&)keyPaths { + return _sectionedResults.add_notification_callback(CollectionCallbackWrapper{block, self}, std::move(keyPaths)); +} + +- (RLMClassInfo *)objectInfo { + return _info; +} + +- (instancetype)resolveInRealm:(RLMRealm *)realm { + return translateErrors([&] { + if (realm.isFrozen) { + return [[RLMSectionedResults alloc] initWithSectionedResults:_sectionedResults.freeze(realm->_realm) + objectInfo:_info->resolve(realm) + keyBlock:_keyBlock]; + } + else { + auto sr = _sectionedResults.freeze(realm->_realm); + sr.reset_section_callback(SectionedResultsKeyProjection {&_info->resolve(realm), _keyBlock}); + return [[RLMSectionedResults alloc] initWithSectionedResults:std::move(sr) + objectInfo:_info->resolve(realm) + keyBlock:_keyBlock]; + } + }); +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + return [self resolveInRealm:_realm.freeze]; +} + +- (instancetype)thaw { + if (!self.frozen) { + return self; + } + return [self resolveInRealm:_realm.thaw]; +} + + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _results; +} + +- (id)objectiveCMetadata { + return _keyBlock; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(id)metadata + realm:(RLMRealm *)realm { + auto results = reference.resolve(realm->_realm); + auto objType = RLMStringDataToNSString(results.get_object_type()); + return [[RLMSectionedResults alloc] initWithResults:std::move(results) + realm:realm + objectInfo:realm->_info[objType] + keyBlock:(RLMSectionedResultsKeyBlock)metadata]; +} + +- (BOOL)isInvalidated { + return translateErrors([&] { return !_sectionedResults.is_valid(); }); +} + +- (NSString *)description { + NSString *objType = @""; + if (_info) { + objType = [NSString stringWithFormat:@"<%@>", _info->rlmObjectSchema.className]; + } + const NSUInteger maxObjects = 100; + auto str = [NSMutableString stringWithFormat:@"RLMSectionedResults%@ <%p> (\n", objType, (void *)self]; + size_t index = 0, skipped = 0; + for (RLMSection *section in self) { + NSString *sub = [section description]; + // Indent child objects + NSString *objDescription = [sub stringByReplacingOccurrencesOfString:@"\n" + withString:@"\n\t"]; + [str appendFormat:@"\t[%@] %@,\n", section.key, objDescription]; + index++; + if (index >= maxObjects) { + skipped = self.count - maxObjects; + break; + } + } + + // Remove last comma and newline characters + if (self.count > 0) { + [str deleteCharactersInRange:NSMakeRange(str.length-2, 2)]; + } + if (skipped) { + [str appendFormat:@"\n\t... %zu objects skipped.", skipped]; + } + [str appendFormat:@"\n)"]; + return str; +} + +- (RLMSectionedResults *)snapshot { + RLMSectionedResults *sr = [RLMSectionedResults new]; + sr->_sectionedResults = _sectionedResults.snapshot(); + sr->_info = _info; + sr->_realm = _realm; + return sr; +} + +- (BOOL)isFrozen { + return translateErrors([&] { return _sectionedResults.is_frozen(); }); +} + +@end + +/// Stores information about a given section during thread handover. +@interface RLMSectionMetadata : NSObject + +@property (nonatomic, strong) RLMSectionedResultsKeyBlock keyBlock; +@property (nonatomic, copy) id sectionKey; + +- (instancetype)initWithKeyBlock:(RLMSectionedResultsKeyBlock)keyBlock + sectionKey:(id)sectionKey; +@end + +@implementation RLMSectionMetadata +- (instancetype)initWithKeyBlock:(RLMSectionedResultsKeyBlock)keyBlock + sectionKey:(id)sectionKey { + if (self = [super init]) { + _keyBlock = keyBlock; + _sectionKey = sectionKey; + } + return self; +} +@end + +@interface RLMSection () +@end + +@implementation RLMSection { + RLMSectionedResults *_parent; + realm::ResultsSection _resultsSection; +} + +- (NSString *)description { + const NSUInteger maxObjects = 100; + auto str = [NSMutableString stringWithFormat:@"RLMSection <%p> (\n", (void *)self]; + size_t index = 0, skipped = 0; + for (id obj in self) { + NSString *sub = [obj description]; + // Indent child objects + NSString *objDescription = [sub stringByReplacingOccurrencesOfString:@"\n" + withString:@"\n\t"]; + [str appendFormat:@"\t[%zu] %@,\n", index++, objDescription]; + if (index >= maxObjects) { + skipped = self.count - maxObjects; + break; + } + } + + // Remove last comma and newline characters + if (self.count > 0) { + [str deleteCharactersInRange:NSMakeRange(str.length-2, 2)]; + } + if (skipped) { + [str appendFormat:@"\n\t... %zu objects skipped.", skipped]; + } + [str appendFormat:@"\n)"]; + return str; +} + +- (instancetype)initWithResultsSection:(realm::ResultsSection&&)resultsSection + parent:(RLMSectionedResults *)parent +{ + if (self = [super init]) { + _resultsSection = std::move(resultsSection); + _parent = parent; + } + return self; +} + +- (id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +- (id)objectAtIndex:(NSUInteger)index { + RLMAccessorContext ctx(*_parent.objectInfo); + return translateErrors([&] { + return ctx.box(_resultsSection[index]); + }); +} + +- (NSUInteger)count { + return translateErrors([&] { + return _resultsSection.size(); + }); +} + +- (id)key { + return translateErrors([&] { + return RLMMixedToObjc(_resultsSection.key()); + }); +} + +- (RLMSectionedResultsEnumerator *)fastEnumerator { + return [[RLMSectionedResultsEnumerator alloc] initWithResultsSection:self]; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + return RLMFastEnumerate(state, len, self); +} + +- (RLMRealm *)realm { + return _parent.realm; +} + +- (RLMClassInfo *)objectInfo { + return _parent.objectInfo; +} + +- (BOOL)isInvalidated { + return translateErrors([&] { return !_resultsSection.is_valid(); }); +} + +- (BOOL)isFrozen { + return translateErrors([&] { return _parent.frozen; }); +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block { + return RLMAddNotificationBlock(self, block, nil, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block keyPaths:(NSArray *)keyPaths { + return RLMAddNotificationBlock(self, block, keyPaths, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, keyPaths, queue); +} +#pragma clang diagnostic pop + +- (realm::NotificationToken)addNotificationCallback:(id)block +keyPaths:(std::optional>>>&&)keyPaths { + return _resultsSection.add_notification_callback(CollectionCallbackWrapper{block, self}, std::move(keyPaths)); +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _parent->_results; +} + +- (RLMSectionMetadata *)objectiveCMetadata { + return [[RLMSectionMetadata alloc] initWithKeyBlock:_parent->_keyBlock + sectionKey:self.key]; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(RLMSectionMetadata *)metadata + realm:(RLMRealm *)realm { + auto results = reference.resolve(realm->_realm); + auto objType = RLMStringDataToNSString(results.get_object_type()); + + RLMSectionedResults *sr = [[RLMSectionedResults alloc] initWithResults:std::move(results) + realm:realm + objectInfo:realm->_info[objType] + keyBlock:metadata.keyBlock]; + return translateErrors([&] { + return [[RLMSection alloc] initWithResultsSection:sr->_sectionedResults[RLMObjcToMixed(metadata.sectionKey)] + parent:sr]; + }); +} + +- (instancetype)resolveInRealm:(RLMRealm *)realm { + return translateErrors([&] { + RLMSectionedResults *sr = realm.isFrozen ? [_parent freeze] : [_parent thaw]; + return [[RLMSection alloc] initWithResultsSection:sr->_sectionedResults[RLMObjcToMixed(self.key)] + parent:sr]; + }); +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + return [self resolveInRealm:_parent.realm.freeze]; +} + +- (instancetype)thaw { + if (!self.frozen) { + return self; + } + return [self resolveInRealm:_parent.realm.thaw]; +} + +@end diff --git a/Pods/Realm/Realm/RLMSet.mm b/Pods/Realm/Realm/RLMSet.mm new file mode 100644 index 0000000..bfe44df --- /dev/null +++ b/Pods/Realm/Realm/RLMSet.mm @@ -0,0 +1,553 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMSet_Private.hpp" + +#import "RLMObjectSchema.h" +#import "RLMObjectStore.h" +#import "RLMObject_Private.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMSchema_Private.h" +#import "RLMSwiftSupport.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +@interface RLMSet () +@end + +@implementation RLMSet { +@public + // Backing set when this instance is unmanaged + NSMutableOrderedSet *_backingCollection; +} + +#pragma mark - Initializers + +- (instancetype)initWithObjectClassName:(__unsafe_unretained NSString *const)objectClassName + keyType:(__unused RLMPropertyType)keyType { + return [self initWithObjectClassName:objectClassName]; +} +- (instancetype)initWithObjectType:(RLMPropertyType)type + optional:(BOOL)optional + keyType:(__unused RLMPropertyType)keyType { + return [self initWithObjectType:type optional:optional]; +} + +- (instancetype)initWithObjectClassName:(__unsafe_unretained NSString *const)objectClassName { + REALM_ASSERT([objectClassName length] > 0); + self = [super init]; + if (self) { + _objectClassName = objectClassName; + _type = RLMPropertyTypeObject; + } + return self; +} + +- (instancetype)initWithObjectType:(RLMPropertyType)type optional:(BOOL)optional { + self = [super init]; + if (self) { + _type = type; + _optional = optional; + } + return self; +} + +- (void)setParent:(RLMObjectBase *)parentObject property:(RLMProperty *)property { + _parentObject = parentObject; + _key = property.name; + _isLegacyProperty = property.isLegacy; +} + +#pragma mark - Convenience wrappers used for all RLMSet types + +- (void)addObjects:(id)objects { + for (id obj in objects) { + [self addObject:obj]; + } +} + +- (void)addObject:(id)object { + RLMSetValidateMatchingObjectType(self, object); + changeSet(self, ^{ + [_backingCollection addObject:object]; + }); +} + +- (void)setObject:(id)newValue atIndexedSubscript:(NSUInteger)index { + REALM_TERMINATE("Replacing objects at an indexed subscript is not supported on RLMSet"); +} + +- (void)setSet:(RLMSet *)set { + for (id obj in set) { + RLMSetValidateMatchingObjectType(self, obj); + } + changeSet(self, ^{ + [_backingCollection removeAllObjects]; + [_backingCollection unionOrderedSet:set->_backingCollection]; + }); +} + +- (void)intersectSet:(RLMSet *)set { + for (id obj in set) { + RLMSetValidateMatchingObjectType(self, obj); + } + changeSet(self, ^{ + [_backingCollection intersectOrderedSet:set->_backingCollection]; + }); +} + +- (void)minusSet:(RLMSet *)set { + for (id obj in set) { + RLMSetValidateMatchingObjectType(self, obj); + } + changeSet(self, ^{ + [_backingCollection minusOrderedSet:set->_backingCollection]; + }); +} + +- (void)unionSet:(RLMSet *)set { + for (id obj in set) { + RLMSetValidateMatchingObjectType(self, obj); + } + changeSet(self, ^{ + [_backingCollection unionOrderedSet:set->_backingCollection]; + }); +} + +- (BOOL)isSubsetOfSet:(RLMSet *)set { + for (id obj in set) { + RLMSetValidateMatchingObjectType(self, obj); + } + return [_backingCollection isSubsetOfOrderedSet:set->_backingCollection]; +} + +- (BOOL)intersectsSet:(RLMSet *)set { + for (id obj in set) { + RLMSetValidateMatchingObjectType(self, obj); + } + return [_backingCollection intersectsOrderedSet:set->_backingCollection]; +} + +- (BOOL)containsObject:(id)obj { + RLMSetValidateMatchingObjectType(self, obj); + return [_backingCollection containsObject:obj]; +} + +- (BOOL)isEqualToSet:(RLMSet *)set { + return [self isEqual:set]; +} + +- (RLMResults *)sortedResultsUsingKeyPath:(NSString *)keyPath ascending:(BOOL)ascending { + return [self sortedResultsUsingDescriptors:@[[RLMSortDescriptor sortDescriptorWithKeyPath:keyPath ascending:ascending]]]; +} + +- (nonnull id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block { + return RLMAddNotificationBlock(self, block, nil, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block + keyPaths:(NSArray *)keyPaths { + return RLMAddNotificationBlock(self, block, keyPaths,nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, keyPaths, queue); +} +#pragma clang diagnostic pop + +#pragma mark - Unmanaged RLMSet implementation + +- (RLMRealm *)realm { + return nil; +} + +- (NSUInteger)count { + return _backingCollection.count; +} + +- (NSArray *)allObjects { + return _backingCollection.array; +} + +// For use with MutableSet subscripting, NSSet does not support +// subscripting while its Swift counterpart `Set` does. +- (id)objectAtIndex:(NSUInteger)index { + validateSetBounds(self, index); + return _backingCollection[index]; +} + +- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + if ([indexes indexGreaterThanOrEqualToIndex:self.count] != NSNotFound) { + return nil; + } + return [_backingCollection objectsAtIndexes:indexes] ?: @[]; +} + +- (id)firstObject { + return _backingCollection.firstObject; +} + +- (id)lastObject { + return _backingCollection.lastObject; +} + +- (BOOL)isInvalidated { + return NO; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(__unused NSUInteger)len { + return RLMUnmanagedFastEnumerate(_backingCollection, state); +} + +static void changeSet(__unsafe_unretained RLMSet *const set, + dispatch_block_t f) { + if (!set->_backingCollection) { + set->_backingCollection = [NSMutableOrderedSet new]; + } + + if (RLMObjectBase *parent = set->_parentObject) { + [parent willChangeValueForKey:set->_key]; + f(); + [parent didChangeValueForKey:set->_key]; + } + else { + f(); + } +} + +static void validateSetBounds(__unsafe_unretained RLMSet *const set, + NSUInteger index, + bool allowOnePastEnd=false) { + NSUInteger max = set->_backingCollection.count + allowOnePastEnd; + if (index >= max) { + @throw RLMException(@"Index %llu is out of bounds (must be less than %llu).", + (unsigned long long)index, (unsigned long long)max); + } +} + +- (void)removeAllObjects { + changeSet(self, ^{ + [_backingCollection removeAllObjects]; + }); +} + +- (void)removeObject:(id)object { + RLMSetValidateMatchingObjectType(self, object); + changeSet(self, ^{ + [_backingCollection removeObject:object]; + }); +} + +- (void)replaceAllObjectsWithObjects:(NSArray *)objects { + changeSet(self, ^{ + [_backingCollection removeAllObjects]; + if (!objects || (id)objects == NSNull.null) { + return; + } + for (id object in objects) { + [_backingCollection addObject:object]; + } + }); +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsWhere:predicateFormat args:args]; + va_end(args); + return results; +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args { + return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (RLMPropertyType)typeForProperty:(NSString *)propertyName { + if ([propertyName isEqualToString:@"self"]) { + return _type; + } + + RLMObjectSchema *objectSchema; + if (_backingCollection.count) { + objectSchema = [_backingCollection[0] objectSchema]; + } + else { + objectSchema = [RLMSchema.partialPrivateSharedSchema schemaForClassName:_objectClassName]; + } + + return RLMValidatedProperty(objectSchema, propertyName).type; +} + +- (id)aggregateProperty:(NSString *)key operation:(NSString *)op method:(SEL)sel { + // Although delegating to valueForKeyPath: here would allow to support + // nested key paths as well, limiting functionality gives consistency + // between unmanaged and managed arrays. + if ([key rangeOfString:@"."].location != NSNotFound) { + @throw RLMException(@"Nested key paths are not supported yet for KVC collection operators."); + } + + if ([op isEqualToString:@"@distinctUnionOfObjects"]) { + @throw RLMException(@"this class does not implement the distinctUnionOfObjects"); + } + + bool allowDate = false; + bool sum = false; + if ([op isEqualToString:@"@min"] || [op isEqualToString:@"@max"]) { + allowDate = true; + } + else if ([op isEqualToString:@"@sum"]) { + sum = true; + } + else if (![op isEqualToString:@"@avg"]) { + // Just delegate to NSSet for all other operators + return [_backingCollection valueForKeyPath:[op stringByAppendingPathExtension:key]]; + } + + RLMPropertyType type = [self typeForProperty:key]; + if (!canAggregate(type, allowDate)) { + NSString *method = sel ? NSStringFromSelector(sel) : op; + if (_type == RLMPropertyTypeObject) { + @throw RLMException(@"%@: is not supported for %@ property '%@.%@'", + method, RLMTypeToString(type), _objectClassName, key); + } + else { + @throw RLMException(@"%@ is not supported for %@%s set", + method, RLMTypeToString(_type), _optional ? "?" : ""); + } + } + + // `valueForKeyPath` on NSSet will only return distinct values, which is an + // issue as the realm::object_store::Set aggregate methods will calculate + // the result based on each element of a property regardless of uniqueness. + // To get around this we will need to use the `array` property of the NSMutableOrderedSet + NSArray *values = [key isEqualToString:@"self"] ? _backingCollection.array : [_backingCollection.array valueForKey:key]; + if (_optional) { + // Filter out NSNull values to match our behavior on managed arrays + NSIndexSet *nonnull = [values indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger, BOOL *) { + return obj != NSNull.null; + }]; + if (nonnull.count < values.count) { + values = [values objectsAtIndexes:nonnull]; + } + } + + id result = [values valueForKeyPath:[op stringByAppendingString:@".self"]]; + return sum && !result ? @0 : result; +} + +static NSSet *toUnorderedSet(id value) { + if (auto orderedSet = RLMDynamicCast(value)) { + return orderedSet.set; + } + return value; +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath characterAtIndex:0] != '@') { + return toUnorderedSet(_backingCollection ? [_backingCollection valueForKeyPath:keyPath] : [super valueForKeyPath:keyPath]); + } + + if (!_backingCollection) { + _backingCollection = [NSMutableOrderedSet new]; + } + + NSUInteger dot = [keyPath rangeOfString:@"."].location; + if (dot == NSNotFound) { + return [_backingCollection valueForKeyPath:keyPath]; + } + + NSString *op = [keyPath substringToIndex:dot]; + NSString *key = [keyPath substringFromIndex:dot + 1]; + return [self aggregateProperty:key operation:op method:nil]; +} + +- (id)valueForKey:(NSString *)key { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @NO; // Unmanaged sets are never invalidated + } + if (!_backingCollection) { + _backingCollection = [NSMutableOrderedSet new]; + } + return toUnorderedSet([_backingCollection valueForKey:key]); +} + +- (void)setValue:(id)value forKey:(NSString *)key { + if ([key isEqualToString:@"self"]) { + RLMSetValidateMatchingObjectType(self, value); + [_backingCollection removeAllObjects]; + [_backingCollection addObject:value]; + return; + } + else if (_type == RLMPropertyTypeObject) { + [_backingCollection setValue:value forKey:key]; + } + else { + [self setValue:value forUndefinedKey:key]; + } +} + +- (id)minOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@min" method:_cmd]; +} + +- (id)maxOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@max" method:_cmd]; +} + +- (id)sumOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@sum" method:_cmd]; +} + +- (id)averageOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@avg" method:_cmd]; +} + +- (BOOL)isEqual:(id)object { + if (auto set = RLMDynamicCast(object)) { + return !set.realm + && ((_backingCollection.count == 0 && set->_backingCollection.count == 0) + || [_backingCollection isEqual:set->_backingCollection]); + } + return NO; +} + +- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options context:(void *)context { + RLMValidateSetObservationKey(keyPath, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +void RLMSetValidateMatchingObjectType(__unsafe_unretained RLMSet *const set, + __unsafe_unretained id const value) { + if (!value && !set->_optional) { + @throw RLMException(@"Invalid nil value for set of '%@'.", + set->_objectClassName ?: RLMTypeToString(set->_type)); + } + if (set->_type != RLMPropertyTypeObject) { + if (!RLMValidateValue(value, set->_type, set->_optional, false, nil)) { + @throw RLMException(@"Invalid value '%@' of type '%@' for expected type '%@%s'.", + value, [value class], RLMTypeToString(set->_type), + set->_optional ? "?" : ""); + } + return; + } + + auto object = RLMDynamicCast(value); + if (!object) { + return; + } + if (!object->_objectSchema) { + @throw RLMException(@"Object cannot be inserted unless the schema is initialized. " + "This can happen if you try to insert objects into a RLMSet / Set from a default value or from an overriden unmanaged initializer (`init()`)."); + } + if (![set->_objectClassName isEqualToString:object->_objectSchema.className] + && (set->_type != RLMPropertyTypeAny)) { + @throw RLMException(@"Object of type '%@' does not match RLMSet type '%@'.", + object->_objectSchema.className, set->_objectClassName); + } +} + +#pragma mark - Key Path Strings + +- (NSString *)propertyKey { + return _key; +} + +#pragma mark - Methods unsupported on unmanaged RLMSet instances + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +- (RLMSectionedResults *)sectionedResultsSortedUsingKeyPath:(NSString *)keyPath + ascending:(BOOL)ascending + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +- (RLMSectionedResults *)sectionedResultsUsingSortDescriptors:(NSArray *)sortDescriptors + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +- (instancetype)freeze { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +- (instancetype)thaw { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMSet`"); +} + +- (id)objectiveCMetadata { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMSet`"); +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(id)metadata + realm:(RLMRealm *)realm { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMSet`"); +} + +#pragma clang diagnostic pop // unused parameter warning + +#pragma mark - Superclass Overrides + +- (NSString *)description { + return [self descriptionWithMaxDepth:RLMDescriptionMaxDepth]; +} + +- (NSString *)descriptionWithMaxDepth:(NSUInteger)depth { + return RLMDescriptionWithMaxDepth(@"RLMSet", self, depth); +} +@end diff --git a/Pods/Realm/Realm/RLMSwiftCollectionBase.mm b/Pods/Realm/Realm/RLMSwiftCollectionBase.mm new file mode 100644 index 0000000..d635c91 --- /dev/null +++ b/Pods/Realm/Realm/RLMSwiftCollectionBase.mm @@ -0,0 +1,172 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2021 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMSwiftCollectionBase.h" + +#import "RLMArray_Private.hpp" +#import "RLMObjectSchema_Private.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMDictionary_Private.hpp" + +@interface RLMArray (KVO) +- (NSArray *)objectsAtIndexes:(__unused NSIndexSet *)indexes; +@end + +// Some of the things declared in the interface are handled by the proxy forwarding +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincomplete-implementation" + +@implementation RLMSwiftCollectionBase + ++ (id)_unmanagedCollection { + return nil; +} + ++ (Class)_backingCollectionType { + REALM_UNREACHABLE(); +} + +- (instancetype)init { + return self; +} + +- (instancetype)initWithCollection:(id)collection { + __rlmCollection = collection; + return self; +} + +- (id)_rlmCollection { + if (!__rlmCollection) { + __rlmCollection = self.class._unmanagedCollection; + } + return __rlmCollection; +} + +- (BOOL)isKindOfClass:(Class)aClass { + return [self._rlmCollection isKindOfClass:aClass] || RLMIsKindOfClass(object_getClass(self), aClass); +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { + return [(id)self._rlmCollection methodSignatureForSelector:sel]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation { + [invocation invokeWithTarget:self._rlmCollection]; +} + +- (id)forwardingTargetForSelector:(__unused SEL)sel { + return self._rlmCollection; +} + +- (BOOL)respondsToSelector:(SEL)aSelector { + return [self._rlmCollection respondsToSelector:aSelector]; +} + +- (void)doesNotRecognizeSelector:(SEL)aSelector { + [(id)self._rlmCollection doesNotRecognizeSelector:aSelector]; +} + +- (BOOL)isEqual:(id)object { + if (auto collection = RLMDynamicCast(object)) { + if (!__rlmCollection) { + return !collection->__rlmCollection.realm && collection->__rlmCollection.count == 0; + } + return [__rlmCollection isEqual:collection->__rlmCollection]; + } + return NO; +} + +- (BOOL)conformsToProtocol:(Protocol *)aProtocol { + return aProtocol == @protocol(NSFastEnumeration) || [self._rlmCollection conformsToProtocol:aProtocol]; +} + +@end + +#pragma clang diagnostic pop + +@implementation RLMLinkingObjectsHandle { + realm::TableKey _tableKey; + realm::ObjKey _objKey; + RLMClassInfo *_info; + RLMRealm *_realm; + RLMProperty *_property; + + RLMResults *_results; +} + +- (instancetype)initWithObject:(RLMObjectBase *)object property:(RLMProperty *)prop { + if (!(self = [super init])) { + return nil; + } + // KeyPath strings will invoke this initializer with an unmanaged object + // so guard against that. + if (object->_realm) { + auto& obj = object->_row; + _tableKey = obj.get_table()->get_key(); + _objKey = obj.get_key(); + _info = object->_info; + _realm = object->_realm; + } + _property = prop; + + return self; +} + +- (instancetype)initWithLinkingObjects:(RLMResults *)linkingObjects { + if (!(self = [super init])) { + return nil; + } + _realm = linkingObjects.realm; + _results = linkingObjects; + + return self; +} + +- (RLMResults *)results { + if (_results) { + return _results; + } + [_realm verifyThread]; + + auto table = _realm.group.get_table(_tableKey); + if (!table->is_valid(_objKey)) { + @throw RLMException(@"Object has been deleted or invalidated."); + } + + auto obj = _realm.group.get_table(_tableKey)->get_object(_objKey); + auto& objectInfo = _realm->_info[_property.objectClassName]; + auto& linkOrigin = _info->objectSchema->computed_properties[_property.index].link_origin_property_name; + auto linkingProperty = objectInfo.objectSchema->property_for_name(linkOrigin); + realm::Results results(_realm->_realm, obj.get_backlink_view(objectInfo.table(), linkingProperty->column_key)); + _results = [RLMLinkingObjects resultsWithObjectInfo:objectInfo results:std::move(results)]; + _realm = nil; + return _results; +} + +- (NSString *)_propertyKey { + return _property.name; +} + +- (BOOL)_isLegacyProperty { + return _property.isLegacy; +} + +@end diff --git a/Pods/Realm/Realm/RLMSwiftSupport.m b/Pods/Realm/Realm/RLMSwiftSupport.m new file mode 100644 index 0000000..e16c79e --- /dev/null +++ b/Pods/Realm/Realm/RLMSwiftSupport.m @@ -0,0 +1,31 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMSwiftSupport.h" + +@implementation RLMSwiftSupport + ++ (BOOL)isSwiftClassName:(NSString *)className { + return [className rangeOfString:@"."].location != NSNotFound; +} + ++ (NSString *)demangleClassName:(NSString *)className { + return [className substringFromIndex:[className rangeOfString:@"."].location + 1]; +} + +@end diff --git a/Pods/Realm/Realm/RLMSwiftValueStorage.mm b/Pods/Realm/Realm/RLMSwiftValueStorage.mm new file mode 100644 index 0000000..80cfc33 --- /dev/null +++ b/Pods/Realm/Realm/RLMSwiftValueStorage.mm @@ -0,0 +1,182 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMSwiftValueStorage.h" + +#import "RLMAccessor.hpp" +#import "RLMObject_Private.hpp" +#import "RLMProperty_Private.h" +#import "RLMUtil.hpp" + +#import + +namespace { +struct SwiftValueStorageBase { + virtual id get() = 0; + virtual void set(id) = 0; + virtual NSString *propertyName() = 0; + virtual ~SwiftValueStorageBase() = default; +}; + +class UnmanagedSwiftValueStorage : public SwiftValueStorageBase { +public: + id get() override { + return _value; + } + + void set(__unsafe_unretained const id newValue) override { + @autoreleasepool { + RLMObjectBase *object = _parent; + [object willChangeValueForKey:_property]; + _value = newValue; + [object didChangeValueForKey:_property]; + } + } + + void attach(__unsafe_unretained RLMObjectBase *const obj, NSString *property) { + if (!_property) { + _property = property; + _parent = obj; + } + } + + NSString *propertyName() override { + return _property; + } + +private: + id _value; + NSString *_property; + __weak RLMObjectBase *_parent; + +}; + +class ManagedSwiftValueStorage : public SwiftValueStorageBase { +public: + ManagedSwiftValueStorage(RLMObjectBase *obj, RLMProperty *prop) + : _realm(obj->_realm) + , _object(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row) + , _columnName(prop.columnName.UTF8String) + , _ctx(*obj->_info) + { + } + + id get() override { + return _object.get_property_value(_ctx, _columnName); + } + + void set(__unsafe_unretained id const value) override { + _object.set_property_value(_ctx, _columnName, value ?: NSNull.null); + } + + NSString *propertyName() override { + // Should never be called on a managed object. + REALM_UNREACHABLE(); + } + +private: + // We have to hold onto a strong reference to the Realm as + // RLMAccessorContext holds a non-retaining one. + __unused RLMRealm *_realm; + realm::Object _object; + std::string _columnName; + RLMAccessorContext _ctx; +}; +} // anonymous namespace + +@interface RLMSwiftValueStorage () { + std::unique_ptr _impl; +} +@end + +@implementation RLMSwiftValueStorage +- (instancetype)init { + return self; +} + +- (BOOL)isKindOfClass:(Class)aClass { + return [RLMGetSwiftValueStorage(self) isKindOfClass:aClass] || RLMIsKindOfClass(object_getClass(self), aClass); +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { + return [RLMGetSwiftValueStorage(self) methodSignatureForSelector:sel]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation { + [invocation invokeWithTarget:RLMGetSwiftValueStorage(self)]; +} + +- (id)forwardingTargetForSelector:(__unused SEL)sel { + return RLMGetSwiftValueStorage(self); +} + +- (BOOL)respondsToSelector:(SEL)aSelector { + return [RLMGetSwiftValueStorage(self) respondsToSelector:aSelector]; +} + +- (void)doesNotRecognizeSelector:(SEL)aSelector { + [RLMGetSwiftValueStorage(self) doesNotRecognizeSelector:aSelector]; +} + +id RLMGetSwiftValueStorage(__unsafe_unretained RLMSwiftValueStorage *const self) { + try { + return self->_impl ? RLMCoerceToNil(self->_impl->get()) : nil; + } + catch (std::exception const& err) { + @throw RLMException(err); + } +} + +void RLMSetSwiftValueStorage(__unsafe_unretained RLMSwiftValueStorage *const self, __unsafe_unretained const id value) { + try { + if (!self->_impl && value) { + self->_impl.reset(new UnmanagedSwiftValueStorage); + } + if (self->_impl) { + self->_impl->set(value); + } + } + catch (std::exception const& err) { + @throw RLMException(err); + } +} + +void RLMInitializeManagedSwiftValueStorage(__unsafe_unretained RLMSwiftValueStorage *const self, + __unsafe_unretained RLMObjectBase *const parent, + __unsafe_unretained RLMProperty *const prop) { + REALM_ASSERT(parent->_realm); + self->_impl.reset(new ManagedSwiftValueStorage(parent, prop)); +} + +void RLMInitializeUnmanagedSwiftValueStorage(__unsafe_unretained RLMSwiftValueStorage *const self, + __unsafe_unretained RLMObjectBase *const parent, + __unsafe_unretained RLMProperty *const prop) { + if (parent->_realm) { + return; + } + if (!self->_impl) { + self->_impl.reset(new UnmanagedSwiftValueStorage); + } + static_cast(*self->_impl).attach(parent, prop.name); +} + +NSString *RLMSwiftValueStorageGetPropertyName(RLMSwiftValueStorage *const self) { + return self->_impl->propertyName(); +} + +@end diff --git a/Pods/Realm/Realm/RLMSyncConfiguration.mm b/Pods/Realm/Realm/RLMSyncConfiguration.mm new file mode 100644 index 0000000..f4b0f73 --- /dev/null +++ b/Pods/Realm/Realm/RLMSyncConfiguration.mm @@ -0,0 +1,281 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMSyncConfiguration_Private.hpp" + +#import "RLMApp_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMError_Private.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMRealmConfiguration_Private.h" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMRealmUtil.hpp" +#import "RLMSchema_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMSyncSession_Private.hpp" +#import "RLMSyncUtil_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import +#import +#import +#import + +using namespace realm; + +namespace { +using ProtocolError = realm::sync::ProtocolError; + +struct CallbackSchema { + bool dynamic; + RLMSchema *customSchema; +}; + +struct BeforeClientResetWrapper : CallbackSchema { + RLMClientResetBeforeBlock block; + void operator()(std::shared_ptr local) { + @autoreleasepool { + if (local->schema_version() != RLMNotVersioned) { + block([RLMRealm realmWithSharedRealm:local schema:customSchema dynamic:dynamic freeze:true]); + } + } + } +}; + +struct AfterClientResetWrapper : CallbackSchema { + RLMClientResetAfterBlock block; + void operator()(std::shared_ptr local, ThreadSafeReference remote, bool) { + @autoreleasepool { + if (local->schema_version() == RLMNotVersioned) { + return; + } + + RLMRealm *localRealm = [RLMRealm realmWithSharedRealm:local + schema:customSchema + dynamic:dynamic + freeze:true]; + RLMRealm *remoteRealm = [RLMRealm realmWithSharedRealm:Realm::get_shared_realm(std::move(remote)) + schema:customSchema + dynamic:dynamic + freeze:false]; + block(localRealm, remoteRealm); + } + } +}; +} // anonymous namespace + +@interface RLMSyncConfiguration () { + std::unique_ptr _config; + RLMSyncErrorReportingBlock _manualClientResetHandler; +} + +@end + +@implementation RLMSyncConfiguration + +@dynamic stopPolicy; + +- (instancetype)initWithRawConfig:(realm::SyncConfig)config path:(std::string const&)path { + if (self = [super init]) { + _config = std::make_unique(std::move(config)); + _path = path; + } + return self; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[RLMSyncConfiguration class]]) { + return NO; + } + RLMSyncConfiguration *that = (RLMSyncConfiguration *)object; + return [self.partitionValue isEqual:that.partitionValue] + && [self.user isEqual:that.user] + && self.stopPolicy == that.stopPolicy; +} + +- (realm::SyncConfig&)rawConfiguration { + return *_config; +} + +- (RLMUser *)user { + RLMApp *app = [RLMApp appWithId:@(_config->user->sync_manager()->app().lock()->config().app_id.data())]; + return [[RLMUser alloc] initWithUser:_config->user app:app]; +} + +- (RLMSyncStopPolicy)stopPolicy { + return translateStopPolicy(_config->stop_policy); +} + +- (void)setStopPolicy:(RLMSyncStopPolicy)stopPolicy { + _config->stop_policy = translateStopPolicy(stopPolicy); +} + +- (RLMClientResetMode)clientResetMode { + return RLMClientResetMode(_config->client_resync_mode); +} + +- (void)setClientResetMode:(RLMClientResetMode)clientResetMode { + _config->client_resync_mode = realm::ClientResyncMode(clientResetMode); +} + +- (RLMClientResetBeforeBlock)beforeClientReset { + if (_config->notify_before_client_reset) { + auto wrapper = _config->notify_before_client_reset.target(); + return wrapper->block; + } else { + return nil; + } +} + +- (void)setBeforeClientReset:(RLMClientResetBeforeBlock)beforeClientReset { + if (!beforeClientReset) { + _config->notify_before_client_reset = nullptr; + } else if (self.clientResetMode == RLMClientResetModeManual) { + @throw RLMException(@"RLMClientResetBeforeBlock reset notifications are not supported in Manual mode. Use RLMSyncConfiguration.manualClientResetHandler or RLMSyncManager.ErrorHandler"); + } else { + _config->freeze_before_reset_realm = false; + _config->notify_before_client_reset = BeforeClientResetWrapper{.block = beforeClientReset}; + } +} + +- (RLMClientResetAfterBlock)afterClientReset { + if (_config->notify_after_client_reset) { + auto wrapper = _config->notify_after_client_reset.target(); + return wrapper->block; + } else { + return nil; + } +} + +- (void)setAfterClientReset:(RLMClientResetAfterBlock)afterClientReset { + if (!afterClientReset) { + _config->notify_after_client_reset = nullptr; + } else if (self.clientResetMode == RLMClientResetModeManual) { + @throw RLMException(@"RLMClientResetAfterBlock reset notifications are not supported in Manual mode. Use RLMSyncConfiguration.manualClientResetHandler or RLMSyncManager.ErrorHandler"); + } else { + _config->notify_after_client_reset = AfterClientResetWrapper{.block = afterClientReset}; + } +} + +- (RLMSyncErrorReportingBlock)manualClientResetHandler { + return _manualClientResetHandler; +} + +- (void)setManualClientResetHandler:(RLMSyncErrorReportingBlock)manualClientReset { + if (!manualClientReset) { + _manualClientResetHandler = nil; + } else if (self.clientResetMode != RLMClientResetModeManual) { + @throw RLMException(@"A manual client reset handler can only be set with RLMClientResetModeManual"); + } else { + _manualClientResetHandler = manualClientReset; + } + [self assignConfigErrorHandler:self.user]; +} + +void RLMSetConfigInfoForClientResetCallbacks(realm::SyncConfig& syncConfig, RLMRealmConfiguration *config) { + if (syncConfig.notify_before_client_reset) { + auto before = syncConfig.notify_before_client_reset.target(); + before->dynamic = config.dynamic; + before->customSchema = config.customSchema; + } + if (syncConfig.notify_after_client_reset) { + auto after = syncConfig.notify_after_client_reset.target(); + after->dynamic = config.dynamic; + after->customSchema = config.customSchema; + } +} + +- (id)partitionValue { + if (!_config->partition_value.empty()) { + return RLMConvertBsonToRLMBSON(realm::bson::parse(_config->partition_value.c_str())); + } + return nil; +} + +- (bool)cancelAsyncOpenOnNonFatalErrors { + return _config->cancel_waits_on_nonfatal_error; +} + +- (void)setCancelAsyncOpenOnNonFatalErrors:(bool)cancelAsyncOpenOnNonFatalErrors { + _config->cancel_waits_on_nonfatal_error = cancelAsyncOpenOnNonFatalErrors; +} + +- (void)assignConfigErrorHandler:(RLMUser *)user { + RLMSyncManager *manager = [user.app syncManager]; + __weak RLMSyncManager *weakManager = manager; + RLMSyncErrorReportingBlock resetHandler = self.manualClientResetHandler; + _config->error_handler = [weakManager, resetHandler](std::shared_ptr errored_session, SyncError error) { + RLMSyncErrorReportingBlock errorHandler; + if (error.is_client_reset_requested()) { + errorHandler = resetHandler; + } + if (!errorHandler) { + @autoreleasepool { + errorHandler = weakManager.errorHandler; + } + } + if (!errorHandler) { + return; + } + NSError *nsError = makeError(std::move(error)); + if (!nsError) { + return; + } + RLMSyncSession *session = [[RLMSyncSession alloc] initWithSyncSession:errored_session]; + dispatch_async(dispatch_get_main_queue(), ^{ + // Keep the SyncSession alive until the callback completes as + // RLMSyncSession only holds a weak reference + static_cast(errored_session); + errorHandler(nsError, session); + }); + }; +}; + +static void setDefaults(SyncConfig& config, RLMUser *user) { + config.client_resync_mode = ClientResyncMode::Recover; + config.stop_policy = SyncSessionStopPolicy::AfterChangesUploaded; + [user.app.syncManager populateConfig:config]; +} + +- (instancetype)initWithUser:(RLMUser *)user + partitionValue:(nullable id)partitionValue { + if (self = [super init]) { + std::stringstream s; + s << RLMConvertRLMBSONToBson(partitionValue); + _config = std::make_unique([user _syncUser], s.str()); + _path = [user pathForPartitionValue:_config->partition_value]; + setDefaults(*_config, user); + [self assignConfigErrorHandler:user]; + } + return self; +} + +- (instancetype)initWithUser:(RLMUser *)user { + if (self = [super init]) { + _config = std::make_unique([user _syncUser], SyncConfig::FLXSyncEnabled{}); + _path = [user pathForFlexibleSync]; + setDefaults(*_config, user); + [self assignConfigErrorHandler:user]; + } + return self; +} + +@end diff --git a/Pods/Realm/Realm/RLMSyncManager.mm b/Pods/Realm/Realm/RLMSyncManager.mm new file mode 100644 index 0000000..e7c38e3 --- /dev/null +++ b/Pods/Realm/Realm/RLMSyncManager.mm @@ -0,0 +1,274 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMSyncManager_Private.hpp" + +#import "RLMApp_Private.hpp" +#import "RLMSyncSession_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMSyncUtil_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +#if !defined(REALM_COCOA_VERSION) +#import "RLMVersion.h" +#endif + +#include + +using namespace realm; + +// NEXT-MAJOR: All the code associated to the logger from sync manager should be removed. +using Level = realm::util::Logger::Level; + +namespace { +Level levelForSyncLogLevel(RLMSyncLogLevel logLevel) { + switch (logLevel) { + case RLMSyncLogLevelOff: return Level::off; + case RLMSyncLogLevelFatal: return Level::fatal; + case RLMSyncLogLevelError: return Level::error; + case RLMSyncLogLevelWarn: return Level::warn; + case RLMSyncLogLevelInfo: return Level::info; + case RLMSyncLogLevelDetail: return Level::detail; + case RLMSyncLogLevelDebug: return Level::debug; + case RLMSyncLogLevelTrace: return Level::trace; + case RLMSyncLogLevelAll: return Level::all; + } + REALM_UNREACHABLE(); // Unrecognized log level. +} + +RLMSyncLogLevel logLevelForLevel(Level logLevel) { + switch (logLevel) { + case Level::off: return RLMSyncLogLevelOff; + case Level::fatal: return RLMSyncLogLevelFatal; + case Level::error: return RLMSyncLogLevelError; + case Level::warn: return RLMSyncLogLevelWarn; + case Level::info: return RLMSyncLogLevelInfo; + case Level::detail: return RLMSyncLogLevelDetail; + case Level::debug: return RLMSyncLogLevelDebug; + case Level::trace: return RLMSyncLogLevelTrace; + case Level::all: return RLMSyncLogLevelAll; + } + REALM_UNREACHABLE(); // Unrecognized log level. +} + +#pragma mark - Loggers + +struct CocoaSyncLogger : public realm::util::Logger { + void do_log(Level, const std::string& message) override { + NSLog(@"Sync: %@", RLMStringDataToNSString(message)); + } +}; + +static std::unique_ptr defaultSyncLogger(realm::util::Logger::Level level) { + auto logger = std::make_unique(); + logger->set_level_threshold(level); + return std::move(logger); +} + +struct CallbackLogger : public realm::util::Logger { + RLMSyncLogFunction logFn; + void do_log(Level level, const std::string& message) override { + @autoreleasepool { + logFn(logLevelForLevel(level), RLMStringDataToNSString(message)); + } + } +}; + +} // anonymous namespace + +std::shared_ptr RLMWrapLogFunction(RLMSyncLogFunction fn) { + auto logger = std::make_shared(); + logger->logFn = fn; + logger->set_level_threshold(Level::all); + return logger; +} + +#pragma mark - RLMSyncManager + +@implementation RLMSyncManager { + RLMUnfairMutex _mutex; + std::shared_ptr _syncManager; + NSDictionary *_customRequestHeaders; + RLMSyncLogFunction _logger; +} + +- (instancetype)initWithSyncManager:(std::shared_ptr)syncManager { + if (self = [super init]) { + [RLMUser _setUpBindingContextFactory]; + _syncManager = syncManager; + return self; + } + return nil; +} + +- (std::weak_ptr)app { + return _syncManager->app(); +} + +- (NSDictionary *)customRequestHeaders { + std::lock_guard lock(_mutex); + return _customRequestHeaders; +} + +- (void)setCustomRequestHeaders:(NSDictionary *)customRequestHeaders { + { + std::lock_guard lock(_mutex); + _customRequestHeaders = customRequestHeaders.copy; + } + + for (auto&& user : _syncManager->all_users()) { + for (auto&& session : user->all_sessions()) { + auto config = session->config(); + config.custom_http_headers.clear(); + for (NSString *key in customRequestHeaders) { + config.custom_http_headers.emplace(key.UTF8String, customRequestHeaders[key].UTF8String); + } + session->update_configuration(std::move(config)); + } + } +} + +- (RLMSyncLogFunction)logger { + std::lock_guard lock(_mutex); + return _logger; +} + +- (void)setLogger:(RLMSyncLogFunction)logFn { + { + std::lock_guard lock(_mutex); + _logger = logFn; + } + if (logFn) { + _syncManager->set_logger_factory([logFn](realm::util::Logger::Level level) { + auto logger = std::make_unique(); + logger->logFn = logFn; + logger->set_level_threshold(level); + return logger; + }); + } + else { + _syncManager->set_logger_factory(defaultSyncLogger); + } +} + +#pragma mark - Passthrough properties + +- (NSString *)userAgent { + return @(_syncManager->config().user_agent_application_info.c_str()); +} + +- (void)setUserAgent:(NSString *)userAgent { + _syncManager->set_user_agent(RLMStringDataWithNSString(userAgent)); +} + +- (RLMSyncTimeoutOptions *)timeoutOptions { + return [[RLMSyncTimeoutOptions alloc] initWithOptions:_syncManager->config().timeouts]; +} + +- (void)setTimeoutOptions:(RLMSyncTimeoutOptions *)timeoutOptions { + _syncManager->set_timeouts(timeoutOptions->_options); +} + +- (RLMSyncLogLevel)logLevel { + return logLevelForLevel(_syncManager->log_level()); +} + +- (void)setLogLevel:(RLMSyncLogLevel)logLevel { + _syncManager->set_log_level(levelForSyncLogLevel(logLevel)); +} + +#pragma mark - Private API + +- (void)resetForTesting { + _errorHandler = nil; + _logger = nil; + _authorizationHeaderName = nil; + _customRequestHeaders = nil; + _syncManager->reset_for_testing(); +} + +- (std::shared_ptr)syncManager { + return _syncManager; +} + +- (void)waitForSessionTermination { + _syncManager->wait_for_sessions_to_terminate(); +} + +- (void)populateConfig:(realm::SyncConfig&)config { + @synchronized (self) { + if (_authorizationHeaderName) { + config.authorization_header_name.emplace(_authorizationHeaderName.UTF8String); + } + [_customRequestHeaders enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *header, BOOL *) { + config.custom_http_headers.emplace(key.UTF8String, header.UTF8String); + }]; + } +} +@end + +#pragma mark - RLMSyncTimeoutOptions + +@implementation RLMSyncTimeoutOptions +- (instancetype)initWithOptions:(realm::SyncClientTimeouts)options { + if (self = [super init]) { + _options = options; + } + return self; +} + +- (NSUInteger)connectTimeout { + return static_cast(_options.connect_timeout); +} +- (void)setConnectTimeout:(NSUInteger)connectTimeout { + _options.connect_timeout = connectTimeout; +} + +- (NSUInteger)connectLingerTime { + return static_cast(_options.connection_linger_time); +} +- (void)setConnectionLingerTime:(NSUInteger)connectionLingerTime { + _options.connection_linger_time = connectionLingerTime; +} + +- (NSUInteger)pingKeepalivePeriod { + return static_cast(_options.ping_keepalive_period); +} +- (void)setPingKeepalivePeriod:(NSUInteger)pingKeepalivePeriod { + _options.ping_keepalive_period = pingKeepalivePeriod; +} + +- (NSUInteger)pongKeepaliveTimeout { + return static_cast(_options.pong_keepalive_timeout); +} +- (void)setPongKeepaliveTimeout:(NSUInteger)pongKeepaliveTimeout { + _options.pong_keepalive_timeout = pongKeepaliveTimeout; +} + +- (NSUInteger)fastReconnectLimit { + return static_cast(_options.fast_reconnect_limit); +} +- (void)setFastReconnectLimit:(NSUInteger)fastReconnectLimit { + _options.fast_reconnect_limit = fastReconnectLimit; +} + +@end diff --git a/Pods/Realm/Realm/RLMSyncSession.mm b/Pods/Realm/Realm/RLMSyncSession.mm new file mode 100644 index 0000000..f181db3 --- /dev/null +++ b/Pods/Realm/Realm/RLMSyncSession.mm @@ -0,0 +1,273 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMSyncSession_Private.hpp" + +#import "RLMApp.h" +#import "RLMRealm_Private.hpp" +#import "RLMError_Private.hpp" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMSyncUtil_Private.hpp" + +#import +#import + +using namespace realm; + +@interface RLMSyncErrorActionToken () { +@public + std::string _originalPath; + BOOL _isValid; +} +@end + +@interface RLMProgressNotificationToken() { + uint64_t _token; + std::shared_ptr _session; +} +@end + +@implementation RLMProgressNotificationToken + +- (void)suppressNextNotification { + // No-op, but implemented in case this token is passed to + // `-[RLMRealm commitWriteTransactionWithoutNotifying:]`. +} + +- (bool)invalidate { + if (_session) { + _session->unregister_progress_notifier(_token); + _session.reset(); + _token = 0; + return true; + } + return false; +} + +- (nullable instancetype)initWithTokenValue:(uint64_t)token + session:(std::shared_ptr)session { + if (token == 0) { + return nil; + } + if (self = [super init]) { + _token = token; + _session = session; + return self; + } + return nil; +} + +@end + +@interface RLMSyncSession () +@property (class, nonatomic, readonly) dispatch_queue_t notificationsQueue; +@property (atomic, readwrite) RLMSyncConnectionState connectionState; +@end + +@implementation RLMSyncSession + ++ (dispatch_queue_t)notificationsQueue { + static auto queue = dispatch_queue_create("io.realm.sync.sessionsNotificationQueue", DISPATCH_QUEUE_SERIAL); + return queue; +} + +static RLMSyncConnectionState convertConnectionState(SyncSession::ConnectionState state) { + switch (state) { + case SyncSession::ConnectionState::Disconnected: return RLMSyncConnectionStateDisconnected; + case SyncSession::ConnectionState::Connecting: return RLMSyncConnectionStateConnecting; + case SyncSession::ConnectionState::Connected: return RLMSyncConnectionStateConnected; + } +} + +- (instancetype)initWithSyncSession:(std::shared_ptr const&)session { + if (self = [super init]) { + _session = session; + _connectionState = convertConnectionState(session->connection_state()); + // No need to save the token as RLMSyncSession always outlives the + // underlying SyncSession + session->register_connection_change_callback([=](auto, auto newState) { + dispatch_async(dispatch_get_main_queue(), ^{ + self.connectionState = convertConnectionState(newState); + }); + }); + return self; + } + return nil; +} + +- (RLMSyncConfiguration *)configuration { + if (auto session = _session.lock()) { + return [[RLMSyncConfiguration alloc] initWithRawConfig:session->config() path:session->path()]; + } + return nil; +} + +- (NSURL *)realmURL { + if (auto session = _session.lock()) { + if (auto url = session->full_realm_url()) { + return [NSURL URLWithString:@(url->c_str())]; + } + } + return nil; +} + +- (RLMUser *)parentUser { + if (auto session = _session.lock()) { + if (auto app = session->user()->sync_manager()->app().lock()) { + auto rlmApp = [RLMApp appWithId:@(app->config().app_id.data())]; + return [[RLMUser alloc] initWithUser:session->user() app:rlmApp]; + } + } + return nil; +} + +- (RLMSyncSessionState)state { + if (auto session = _session.lock()) { + if (session->state() == SyncSession::State::Inactive) { + return RLMSyncSessionStateInactive; + } + return RLMSyncSessionStateActive; + } + return RLMSyncSessionStateInvalid; +} + +- (void)suspend { + if (auto session = _session.lock()) { + session->force_close(); + } +} + +- (void)resume { + if (auto session = _session.lock()) { + session->revive_if_needed(); + } +} + +- (void)pause { + // NEXT-MAJOR: this is what suspend should be + if (auto session = _session.lock()) { + session->pause(); + } +} + +- (void)unpause { + // NEXT-MAJOR: this is what resume should be + if (auto session = _session.lock()) { + session->resume(); + } +} + +static util::UniqueFunction wrapCompletion(dispatch_queue_t queue, + void (^callback)(NSError *)) { + queue = queue ?: dispatch_get_main_queue(); + return [=](Status status) { + NSError *error = makeError(status); + dispatch_async(queue, ^{ + callback(error); + }); + }; +} + +- (BOOL)waitForUploadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback { + if (auto session = _session.lock()) { + session->wait_for_upload_completion(wrapCompletion(queue, callback)); + return YES; + } + return NO; +} + +- (BOOL)waitForDownloadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback { + if (auto session = _session.lock()) { + session->wait_for_download_completion(wrapCompletion(queue, callback)); + return YES; + } + return NO; +} + +- (RLMProgressNotificationToken *)addProgressNotificationForDirection:(RLMSyncProgressDirection)direction + mode:(RLMSyncProgressMode)mode + block:(RLMProgressNotificationBlock)block { + if (auto session = _session.lock()) { + dispatch_queue_t queue = RLMSyncSession.notificationsQueue; + auto notifier_direction = (direction == RLMSyncProgressDirectionUpload + ? SyncSession::ProgressDirection::upload + : SyncSession::ProgressDirection::download); + bool is_streaming = (mode == RLMSyncProgressModeReportIndefinitely); + uint64_t token = session->register_progress_notifier([=](uint64_t transferred, uint64_t transferrable) { + dispatch_async(queue, ^{ + block((NSUInteger)transferred, (NSUInteger)transferrable); + }); + }, notifier_direction, is_streaming); + return [[RLMProgressNotificationToken alloc] initWithTokenValue:token session:session]; + } + return nil; +} + ++ (void)immediatelyHandleError:(RLMSyncErrorActionToken *)token syncManager:(RLMSyncManager *)syncManager { + if (!token->_isValid) { + return; + } + token->_isValid = NO; + + [syncManager syncManager]->immediately_run_file_actions(std::move(token->_originalPath)); +} + ++ (nullable RLMSyncSession *)sessionForRealm:(RLMRealm *)realm { + auto& config = realm->_realm->config().sync_config; + if (!config) { + return nil; + } + if (auto session = config->user->session_for_on_disk_path(realm->_realm->config().path)) { + return [[RLMSyncSession alloc] initWithSyncSession:session]; + } + return nil; +} + +- (NSString *)description { + return [NSString stringWithFormat: + @" {\n" + "\tstate = %d;\n" + "\tconnectionState = %d;\n" + "\trealmURL = %@;\n" + "\tuser = %@;\n" + "}", + (__bridge void *)self, + static_cast(self.state), + static_cast(self.connectionState), + self.realmURL, + self.parentUser.identifier]; +} + +@end + +// MARK: - Error action token + +@implementation RLMSyncErrorActionToken + +- (instancetype)initWithOriginalPath:(std::string)originalPath { + if (self = [super init]) { + _isValid = YES; + _originalPath = std::move(originalPath); + return self; + } + return nil; +} + +@end diff --git a/Pods/Realm/Realm/RLMSyncSubscription.mm b/Pods/Realm/Realm/RLMSyncSubscription.mm new file mode 100644 index 0000000..a31c26b --- /dev/null +++ b/Pods/Realm/Realm/RLMSyncSubscription.mm @@ -0,0 +1,535 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2021 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMSyncSubscription_Private.hpp" + +#import "RLMError_Private.hpp" +#import "RLMObjectId_Private.hpp" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +#pragma mark - Subscription + +@interface RLMSyncSubscription () { + std::unique_ptr _subscription; + RLMSyncSubscriptionSet *_subscriptionSet; +} +@end + +@implementation RLMSyncSubscription + +- (instancetype)initWithSubscription:(realm::sync::Subscription)subscription subscriptionSet:(RLMSyncSubscriptionSet *)subscriptionSet { + if (self = [super init]) { + _subscription = std::make_unique(subscription); + _subscriptionSet = subscriptionSet; + return self; + } + return nil; +} + +- (RLMObjectId *)identifier { + return [[RLMObjectId alloc] initWithValue:_subscription->id]; +} + +- (nullable NSString *)name { + auto name = _subscription->name; + if (name) { + return @(name->c_str()); + } + return nil; +} + +- (NSDate *)createdAt { + return RLMTimestampToNSDate(_subscription->created_at); +} + +- (NSDate *)updatedAt { + return RLMTimestampToNSDate(_subscription->updated_at); +} + +- (NSString *)queryString { + return @(_subscription->query_string.c_str()); +} + +- (NSString *)objectClassName { + return @(_subscription->object_class_name.c_str()); +} + +- (void)updateSubscriptionWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + [self updateSubscriptionWhere:predicateFormat + args:args]; + va_end(args); +} + +- (void)updateSubscriptionWhere:(NSString *)predicateFormat + args:(va_list)args { + [self updateSubscriptionWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (void)updateSubscriptionWithPredicate:(NSPredicate *)predicate { + if (self.name != nil) { + [_subscriptionSet addSubscriptionWithClassName:self.objectClassName + subscriptionName:self.name + predicate:predicate + updateExisting:true]; + } + else { + RLMSyncSubscription *foundSubscription = [_subscriptionSet subscriptionWithClassName:self.objectClassName where:self.queryString]; + if (foundSubscription) { + [_subscriptionSet removeSubscription:foundSubscription]; + [_subscriptionSet addSubscriptionWithClassName:self.objectClassName + predicate:predicate]; + } else { + @throw RLMException(@"Cannot update a non-existent subscription."); + } + } +} + +@end + +#pragma mark - SubscriptionSet + +@interface RLMSyncSubscriptionSet () { + std::unique_ptr _subscriptionSet; + std::unique_ptr _mutableSubscriptionSet; + NSHashTable *_enumerators; +} +@end + +@interface RLMSyncSubscriptionEnumerator() { + // The buffer supplied by fast enumeration does not retain the objects given + // to it, but because we create objects on-demand and don't want them + // autoreleased (a table can have more rows than the device has memory for + // accessor objects) we need a thing to retain them. + id _strongBuffer[16]; +} +@end + +@implementation RLMSyncSubscriptionEnumerator + +- (instancetype)initWithSubscriptionSet:(RLMSyncSubscriptionSet *)subscriptionSet { + if (self = [super init]) { + _subscriptionSet = subscriptionSet; + return self; + } + return nil; +} +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + count:(NSUInteger)len { + NSUInteger batchCount = 0, count = [_subscriptionSet count]; + for (NSUInteger index = state->state; index < count && batchCount < len; ++index) { + auto subscription = [_subscriptionSet objectAtIndex:index]; + _strongBuffer[batchCount] = subscription; + batchCount++; + } + + for (NSUInteger i = batchCount; i < len; ++i) { + _strongBuffer[i] = nil; + } + + if (batchCount == 0) { + // Release our data if we're done, as we're autoreleased and so may + // stick around for a while + if (_subscriptionSet) { + _subscriptionSet = nil; + } + } + + + state->itemsPtr = (__unsafe_unretained id *)(void *)_strongBuffer; + state->state += batchCount; + state->mutationsPtr = state->extra+1; + + return batchCount; +} + +@end + +NSUInteger RLMFastEnumerate(NSFastEnumerationState *state, + NSUInteger len, + RLMSyncSubscriptionSet *collection) { + __autoreleasing RLMSyncSubscriptionEnumerator *enumerator; + if (state->state == 0) { + enumerator = collection.fastEnumerator; + state->extra[0] = (long)enumerator; + state->extra[1] = collection.count; + } + else { + enumerator = (__bridge id)(void *)state->extra[0]; + } + + return [enumerator countByEnumeratingWithState:state count:len]; +} + +@implementation RLMSyncSubscriptionSet { + std::mutex _collectionEnumeratorMutex; + RLMRealm *_realm; +} + +- (instancetype)initWithSubscriptionSet:(realm::sync::SubscriptionSet)subscriptionSet + realm:(RLMRealm *)realm { + if (self = [super init]) { + _subscriptionSet = std::make_unique(subscriptionSet); + _realm = realm; + return self; + } + return nil; +} + +- (RLMSyncSubscriptionEnumerator *)fastEnumerator { + return [[RLMSyncSubscriptionEnumerator alloc] initWithSubscriptionSet:self]; +} + +- (NSUInteger)count { + return _subscriptionSet->size(); +} + +- (nullable NSError *)error { + _subscriptionSet->refresh(); + NSString *errorMessage = RLMStringDataToNSString(_subscriptionSet->error_str()); + if (errorMessage.length == 0) { + return nil; + } + return [[NSError alloc] initWithDomain:RLMSyncErrorDomain + code:RLMSyncErrorInvalidFlexibleSyncSubscriptions + userInfo:@{NSLocalizedDescriptionKey: errorMessage}]; +} + +- (RLMSyncSubscriptionState)state { + _subscriptionSet->refresh(); + switch (_subscriptionSet->state()) { + case realm::sync::SubscriptionSet::State::Uncommitted: + case realm::sync::SubscriptionSet::State::Pending: + case realm::sync::SubscriptionSet::State::Bootstrapping: + case realm::sync::SubscriptionSet::State::AwaitingMark: + return RLMSyncSubscriptionStatePending; + case realm::sync::SubscriptionSet::State::Complete: + return RLMSyncSubscriptionStateComplete; + case realm::sync::SubscriptionSet::State::Error: + return RLMSyncSubscriptionStateError; + case realm::sync::SubscriptionSet::State::Superseded: + return RLMSyncSubscriptionStateSuperseded; + } +} + +#pragma mark - Batch Update subscriptions + +- (void)update:(__attribute__((noescape)) void(^)(void))block { + return [self update:block onComplete:nil]; +} + +- (void)update:(__attribute__((noescape)) void(^)(void))block onComplete:(void(^)(NSError *))completionBlock { + if (_mutableSubscriptionSet) { + @throw RLMException(@"Cannot initiate a write transaction on subscription set that is already being updated."); + } + _mutableSubscriptionSet = std::make_unique(_subscriptionSet->make_mutable_copy()); + realm::util::ScopeExit cleanup([&]() noexcept { + if (_mutableSubscriptionSet) { + _mutableSubscriptionSet = nullptr; + _subscriptionSet->refresh(); + } + }); + + block(); + + try { + _subscriptionSet = std::make_unique(std::move(*_mutableSubscriptionSet).commit()); + _mutableSubscriptionSet = nullptr; + } + catch (realm::Exception const& ex) { + @throw RLMException(ex); + } + catch (std::exception const& ex) { + @throw RLMException(ex); + } + + if (completionBlock) { + [self waitForSynchronizationOnQueue:nil completionBlock:completionBlock]; + } +} + +- (void)waitForSynchronizationOnQueue:(nullable dispatch_queue_t)queue + completionBlock:(void(^)(NSError *))completionBlock { + _subscriptionSet->get_state_change_notification(realm::sync::SubscriptionSet::State::Complete) + .get_async([completionBlock, queue](realm::StatusWith state) noexcept { + if (queue) { + return dispatch_async(queue, ^{ + completionBlock(makeError(state)); + }); + } + return completionBlock(makeError(state)); + }); +} + +#pragma mark - Find subscription + +- (nullable RLMSyncSubscription *)subscriptionWithName:(NSString *)name { + auto subscription = _subscriptionSet->find([name UTF8String]); + if (subscription) { + return [[RLMSyncSubscription alloc] initWithSubscription:*subscription + subscriptionSet:self]; + } + return nil; +} + +- (nullable RLMSyncSubscription *)subscriptionWithClassName:(NSString *)objectClassName + where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + return [self subscriptionWithClassName:objectClassName + where:predicateFormat + args:args]; + va_end(args); +} + +- (nullable RLMSyncSubscription *)subscriptionWithClassName:(NSString *)objectClassName + where:(NSString *)predicateFormat + args:(va_list)args { + return [self subscriptionWithClassName:objectClassName + predicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (nullable RLMSyncSubscription *)subscriptionWithClassName:(NSString *)objectClassName + predicate:(NSPredicate *)predicate { + RLMClassInfo& info = _realm->_info[objectClassName]; + auto query = RLMPredicateToQuery(predicate, info.rlmObjectSchema, _realm.schema, _realm.group); + auto subscription = _subscriptionSet->find(query); + if (subscription) { + return [[RLMSyncSubscription alloc] initWithSubscription:*subscription + subscriptionSet:self]; + } + return nil; +} + + +#pragma mark - Add a Subscription + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + return [self addSubscriptionWithClassName:objectClassName + where:predicateFormat + args:args]; + va_end(args); +} + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + where:(NSString *)predicateFormat + args:(va_list)args { + [self addSubscriptionWithClassName:objectClassName + subscriptionName:nil + predicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + subscriptionName:(NSString *)name + where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + return [self addSubscriptionWithClassName:objectClassName + subscriptionName:name + where:predicateFormat + args:args]; + va_end(args); +} + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + subscriptionName:(NSString *)name + where:(NSString *)predicateFormat + args:(va_list)args { + [self addSubscriptionWithClassName:objectClassName + subscriptionName:name + predicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; + +} + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + predicate:(NSPredicate *)predicate { + return [self addSubscriptionWithClassName:objectClassName + subscriptionName:nil + predicate:predicate]; +} + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + subscriptionName:(nullable NSString *)name + predicate:(NSPredicate *)predicate { + return [self addSubscriptionWithClassName:objectClassName + subscriptionName:name + predicate:predicate + updateExisting:false]; +} + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + subscriptionName:(nullable NSString *)name + predicate:(NSPredicate *)predicate + updateExisting:(BOOL)updateExisting { + [self verifyInWriteTransaction]; + + RLMClassInfo& info = _realm->_info[objectClassName]; + auto query = RLMPredicateToQuery(predicate, info.rlmObjectSchema, _realm.schema, _realm.group); + + if (name) { + if (updateExisting || !_mutableSubscriptionSet->find(name.UTF8String)) { + _mutableSubscriptionSet->insert_or_assign(name.UTF8String, query); + } + else { + @throw RLMException(@"A subscription named '%@' already exists. If you meant to update the existing subscription please use the `update` method.", name); + } + } + else { + _mutableSubscriptionSet->insert_or_assign(query); + } +} + +#pragma mark - Remove Subscription + +- (void)removeSubscriptionWithName:(NSString *)name { + [self verifyInWriteTransaction]; + + auto subscription = _subscriptionSet->find([name UTF8String]); + if (subscription) { + _mutableSubscriptionSet->erase(subscription->name); + } +} + +- (void)removeSubscriptionWithClassName:(NSString *)objectClassName + where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + [self removeSubscriptionWithClassName:objectClassName + where:predicateFormat + args:args]; + va_end(args); +} + +- (void)removeSubscriptionWithClassName:(NSString *)objectClassName + where:(NSString *)predicateFormat + args:(va_list)args { + [self removeSubscriptionWithClassName:objectClassName + predicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (void)removeSubscriptionWithClassName:(NSString *)objectClassName + predicate:(NSPredicate *)predicate { + [self verifyInWriteTransaction]; + + RLMClassInfo& info = _realm->_info[objectClassName]; + auto query = RLMPredicateToQuery(predicate, info.rlmObjectSchema, _realm.schema, _realm.group); + auto subscription = _subscriptionSet->find(query); + if (subscription) { + _mutableSubscriptionSet->erase(query); + } +} + +- (void)removeSubscription:(RLMSyncSubscription *)subscription { + [self verifyInWriteTransaction]; + + for (auto it = _mutableSubscriptionSet->begin(); it != _mutableSubscriptionSet->end();) { + if (it->id == subscription.identifier.value) { + it = _mutableSubscriptionSet->erase(it); + return; + } + it++; + } +} + +#pragma mark - Remove Subscriptions + +- (void)removeAllSubscriptions { + [self verifyInWriteTransaction]; + _mutableSubscriptionSet->clear(); +} + +- (void)removeAllSubscriptionsWithClassName:(NSString *)className { + [self verifyInWriteTransaction]; + + for (auto it = _mutableSubscriptionSet->begin(); it != _mutableSubscriptionSet->end();) { + if (it->object_class_name == [className UTF8String]) { + it = _mutableSubscriptionSet->erase(it); + } + else { + it++; + } + } +} + +#pragma mark - NSFastEnumerator + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + return RLMFastEnumerate(state, len, self); +} + +#pragma mark - SubscriptionSet Collection + +- (RLMSyncSubscription *)objectAtIndex:(NSUInteger)index { + auto size = _subscriptionSet->size(); + if (index >= size) { + @throw RLMException(@"Index %llu is out of bounds (must be less than %llu).", + (unsigned long long)index, (unsigned long long)size); + } + + return [[RLMSyncSubscription alloc]initWithSubscription:_subscriptionSet->at(size_t(index)) + subscriptionSet:self]; +} + +- (RLMSyncSubscription *)firstObject { + if (_subscriptionSet->size() < 1) { + return nil; + } + return [[RLMSyncSubscription alloc]initWithSubscription:_subscriptionSet->at(size_t(0)) + subscriptionSet:self]; +} + +- (RLMSyncSubscription *)lastObject { + if (_subscriptionSet->size() < 1) { + return nil; + } + + return [[RLMSyncSubscription alloc]initWithSubscription:_subscriptionSet->at(_subscriptionSet->size()-1) + subscriptionSet:self]; +} + +#pragma mark - Subscript + +- (id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +#pragma mark - Private API + +- (uint64_t)version { + return _subscriptionSet->version(); +} + +- (void)verifyInWriteTransaction { + if (_mutableSubscriptionSet == nil) { + @throw RLMException(@"Can only add, remove, or update subscriptions within a write subscription block."); + } +} + +@end diff --git a/Pods/Realm/Realm/RLMSyncUtil.mm b/Pods/Realm/Realm/RLMSyncUtil.mm new file mode 100644 index 0000000..8246f8d --- /dev/null +++ b/Pods/Realm/Realm/RLMSyncUtil.mm @@ -0,0 +1,54 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMSyncUtil_Private.hpp" + +#import "RLMUser_Private.hpp" + +NSString *const kRLMSyncPathOfRealmBackupCopyKey = @"recovered_realm_location_path"; +NSString *const kRLMSyncErrorActionTokenKey = @"error_action_token"; + +#pragma mark - C++ APIs + +using namespace realm; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +static_assert((int)RLMClientResetModeDiscardLocal == (int)realm::ClientResyncMode::DiscardLocal); +#pragma clang diagnostic pop +static_assert((int)RLMClientResetModeDiscardUnsyncedChanges == (int)realm::ClientResyncMode::DiscardLocal); +static_assert((int)RLMClientResetModeRecoverUnsyncedChanges == (int)realm::ClientResyncMode::Recover); +static_assert((int)RLMClientResetModeRecoverOrDiscardUnsyncedChanges == (int)realm::ClientResyncMode::RecoverOrDiscard); +static_assert((int)RLMClientResetModeManual == (int)realm::ClientResyncMode::Manual); + +static_assert(int(RLMSyncStopPolicyImmediately) == int(SyncSessionStopPolicy::Immediately)); +static_assert(int(RLMSyncStopPolicyLiveIndefinitely) == int(SyncSessionStopPolicy::LiveIndefinitely)); +static_assert(int(RLMSyncStopPolicyAfterChangesUploaded) == int(SyncSessionStopPolicy::AfterChangesUploaded)); + +SyncSessionStopPolicy translateStopPolicy(RLMSyncStopPolicy stopPolicy) { + return static_cast(stopPolicy); +} + +RLMSyncStopPolicy translateStopPolicy(SyncSessionStopPolicy stopPolicy) { + return static_cast(stopPolicy); +} + +CocoaSyncUserContext& context_for(const std::shared_ptr& user) +{ + return *std::static_pointer_cast(user->binding_context()); +} diff --git a/Pods/Realm/Realm/RLMThreadSafeReference.mm b/Pods/Realm/Realm/RLMThreadSafeReference.mm new file mode 100644 index 0000000..d582332 --- /dev/null +++ b/Pods/Realm/Realm/RLMThreadSafeReference.mm @@ -0,0 +1,69 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +@implementation RLMThreadSafeReference { + realm::ThreadSafeReference _reference; + id _metadata; + Class _type; +} + +- (instancetype)initWithThreadConfined:(id)threadConfined { + if (!(self = [super init])) { + return nil; + } + + REALM_ASSERT_DEBUG([threadConfined conformsToProtocol:@protocol(RLMThreadConfined)]); + if (![threadConfined conformsToProtocol:@protocol(RLMThreadConfined_Private)]) { + @throw RLMException(@"Illegal custom conformance to `RLMThreadConfined` by `%@`", threadConfined.class); + } else if (threadConfined.invalidated) { + @throw RLMException(@"Cannot construct reference to invalidated object"); + } else if (!threadConfined.realm) { + @throw RLMException(@"Cannot construct reference to unmanaged object, " + "which can be passed across threads directly"); + } + + RLMTranslateError([&] { + _reference = [(id)threadConfined makeThreadSafeReference]; + _metadata = ((id)threadConfined).objectiveCMetadata; + }); + _type = threadConfined.class; + + return self; +} + ++ (instancetype)referenceWithThreadConfined:(id)threadConfined { + return [[self alloc] initWithThreadConfined:threadConfined]; +} + +- (id)resolveReferenceInRealm:(RLMRealm *)realm { + if (!_reference) { + @throw RLMException(@"Can only resolve a thread safe reference once."); + } + return RLMTranslateError([&] { + return [_type objectWithThreadSafeReference:std::move(_reference) metadata:_metadata realm:realm]; + }); +} + +- (BOOL)isInvalidated { + return !_reference; +} + +@end diff --git a/Pods/Realm/Realm/RLMUUID.mm b/Pods/Realm/Realm/RLMUUID.mm new file mode 100644 index 0000000..2a2f2d6 --- /dev/null +++ b/Pods/Realm/Realm/RLMUUID.mm @@ -0,0 +1,34 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMUUID_Private.hpp" + +#import + +@implementation NSUUID (RLMUUIDSupport) + +- (instancetype)initWithRealmUUID:(realm::UUID)rUuid { + self = [self initWithUUIDBytes:rUuid.to_bytes().data()]; + return self; +} + +- (realm::UUID)rlm_uuidValue { + return realm::UUID(self.UUIDString.UTF8String); +} + +@end diff --git a/Pods/Realm/Realm/RLMUpdateChecker.mm b/Pods/Realm/Realm/RLMUpdateChecker.mm new file mode 100644 index 0000000..6e54746 --- /dev/null +++ b/Pods/Realm/Realm/RLMUpdateChecker.mm @@ -0,0 +1,60 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMUpdateChecker.hpp" + +#import "RLMRealm.h" +#import "RLMUtil.hpp" + +#if TARGET_IPHONE_SIMULATOR && !defined(REALM_COCOA_VERSION) +#import "RLMVersion.h" +#endif + +void RLMCheckForUpdates() { +#if TARGET_IPHONE_SIMULATOR + if (getenv("REALM_DISABLE_UPDATE_CHECKER") || RLMIsRunningInPlayground()) { + return; + } + + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"alpha|beta|rc" + options:(NSRegularExpressionOptions)0 + error:nil]; + NSUInteger numberOfMatches = [regex numberOfMatchesInString:REALM_COCOA_VERSION + options:(NSMatchingOptions)0 + range:NSMakeRange(0, REALM_COCOA_VERSION.length)]; + + if (numberOfMatches > 0) { + // pre-release version, skip update checking + return; + } + + auto handler = ^(NSData *data, NSURLResponse *response, NSError *error) { + if (error || ((NSHTTPURLResponse *)response).statusCode != 200) { + return; + } + + NSString *latestVersion = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (![REALM_COCOA_VERSION isEqualToString:latestVersion]) { + NSLog(@"Version %@ of Realm is now available: https://github.com/realm/realm-swift/blob/v%@/CHANGELOG.md", latestVersion, latestVersion); + } + }; + + NSString *url = [NSString stringWithFormat:@"https://static.realm.io/update/cocoa?%@", REALM_COCOA_VERSION]; + [[NSURLSession.sharedSession dataTaskWithURL:[NSURL URLWithString:url] completionHandler:handler] resume]; +#endif +} diff --git a/Pods/Realm/Realm/RLMUpdateResult.mm b/Pods/Realm/Realm/RLMUpdateResult.mm new file mode 100644 index 0000000..cd73ec4 --- /dev/null +++ b/Pods/Realm/Realm/RLMUpdateResult.mm @@ -0,0 +1,38 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMUpdateResult_Private.hpp" + +#import "RLMBSON_Private.hpp" +#import "RLMUtil.hpp" + +@implementation RLMUpdateResult + +- (instancetype)initWithUpdateResult:(realm::app::MongoCollection::UpdateResult)updateResult { + if (self = [super init]) { + _matchedCount = updateResult.matched_count; + _modifiedCount = updateResult.modified_count; + if (updateResult.upserted_id) { + _documentId = RLMConvertBsonToRLMBSON(*updateResult.upserted_id); + _objectId = RLMDynamicCast(_documentId); + } + } + return self; +} + +@end diff --git a/Pods/Realm/Realm/RLMUser.mm b/Pods/Realm/Realm/RLMUser.mm new file mode 100644 index 0000000..5e17359 --- /dev/null +++ b/Pods/Realm/Realm/RLMUser.mm @@ -0,0 +1,498 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMUser_Private.hpp" + +#import "RLMAPIKeyAuth.h" +#import "RLMApp_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMCredentials_Private.hpp" +#import "RLMMongoClient_Private.hpp" +#import "RLMRealmConfiguration_Private.h" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMSyncSession_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import +#import + +using namespace realm; + +@interface RLMUser () { + std::shared_ptr _user; +} +@end + +@implementation RLMUserSubscriptionToken { + std::shared_ptr _user; + std::optional::Token> _token; +} + +- (instancetype)initWithUser:(std::shared_ptr)user token:(realm::Subscribable::Token&&)token { + if (self = [super init]) { + _user = std::move(user); + _token = std::move(token); + } + return self; +} + +- (void)unsubscribe { + _token.reset(); + _user.reset(); +} +@end + +@implementation RLMUser + +#pragma mark - API + +- (instancetype)initWithUser:(std::shared_ptr)user + app:(RLMApp *)app { + if (self = [super init]) { + _user = user; + _app = app; + return self; + } + return nil; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[RLMUser class]]) { + return NO; + } + return _user == ((RLMUser *)object)->_user; +} + +- (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id)partitionValue { + return [self configurationWithPartitionValue:partitionValue clientResetMode:RLMClientResetModeRecoverUnsyncedChanges]; +} + +- (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id)partitionValue + clientResetMode:(RLMClientResetMode)clientResetMode { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self + partitionValue:partitionValue]; + syncConfig.clientResetMode = clientResetMode; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id)partitionValue + clientResetMode:(RLMClientResetMode)clientResetMode + notifyBeforeReset:(nullable RLMClientResetBeforeBlock)beforeResetBlock + notifyAfterReset:(nullable RLMClientResetAfterBlock)afterResetBlock { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self + partitionValue:partitionValue]; + syncConfig.clientResetMode = clientResetMode; + syncConfig.beforeClientReset = beforeResetBlock; + syncConfig.afterClientReset = afterResetBlock; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id)partitionValue + clientResetMode:(RLMClientResetMode)clientResetMode + manualClientResetHandler:(nullable RLMSyncErrorReportingBlock)manualClientResetHandler { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self + partitionValue:partitionValue]; + syncConfig.clientResetMode = clientResetMode; + syncConfig.manualClientResetHandler = manualClientResetHandler; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)flexibleSyncConfiguration { + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.syncConfiguration = [[RLMSyncConfiguration alloc] initWithUser:self]; + return config; +} + +- (RLMRealmConfiguration *)flexibleSyncConfigurationWithClientResetMode:(RLMClientResetMode)clientResetMode + notifyBeforeReset:(nullable RLMClientResetBeforeBlock)beforeResetBlock + notifyAfterReset:(nullable RLMClientResetAfterBlock)afterResetBlock { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self]; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + syncConfig.clientResetMode = clientResetMode; + syncConfig.beforeClientReset = beforeResetBlock; + syncConfig.afterClientReset = afterResetBlock; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)flexibleSyncConfigurationWithClientResetMode:(RLMClientResetMode)clientResetMode + manualClientResetHandler:(nullable RLMSyncErrorReportingBlock)manualClientResetHandler { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self]; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + syncConfig.clientResetMode = clientResetMode; + syncConfig.manualClientResetHandler = manualClientResetHandler; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)flexibleSyncConfigurationWithInitialSubscriptions:(RLMFlexibleSyncInitialSubscriptionsBlock)initialSubscriptions + rerunOnOpen:(BOOL)rerunOnOpen { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self]; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.initialSubscriptions = initialSubscriptions; + config.rerunOnOpen = rerunOnOpen; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)flexibleSyncConfigurationWithInitialSubscriptions:(RLMFlexibleSyncInitialSubscriptionsBlock)initialSubscriptions + rerunOnOpen:(BOOL)rerunOnOpen + clientResetMode:(RLMClientResetMode)clientResetMode + notifyBeforeReset:(nullable RLMClientResetBeforeBlock)beforeResetBlock + notifyAfterReset:(nullable RLMClientResetAfterBlock)afterResetBlock { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self]; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + syncConfig.clientResetMode = clientResetMode; + syncConfig.beforeClientReset = beforeResetBlock; + syncConfig.afterClientReset = afterResetBlock; + config.initialSubscriptions = initialSubscriptions; + config.rerunOnOpen = rerunOnOpen; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)flexibleSyncConfigurationWithInitialSubscriptions:(RLMFlexibleSyncInitialSubscriptionsBlock)initialSubscriptions + rerunOnOpen:(BOOL)rerunOnOpen + clientResetMode:(RLMClientResetMode)clientResetMode + manualClientResetHandler:(nullable RLMSyncErrorReportingBlock)manualClientResetHandler { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self]; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + syncConfig.clientResetMode = clientResetMode; + syncConfig.manualClientResetHandler = manualClientResetHandler; + config.initialSubscriptions = initialSubscriptions; + config.rerunOnOpen = rerunOnOpen; + config.syncConfiguration = syncConfig; + return config; +} + +- (void)logOut { + if (!_user) { + return; + } + _user->log_out(); +} + +- (BOOL)isLoggedIn { + return _user->is_logged_in(); +} + +- (void)invalidate { + if (!_user) { + return; + } + _user = nullptr; +} + +- (std::string)pathForPartitionValue:(std::string const&)value { + if (!_user) { + return ""; + } + + SyncConfig config(_user, value); + auto path = _user->sync_manager()->path_for_realm(config, value); + if ([NSFileManager.defaultManager fileExistsAtPath:@(path.c_str())]) { + return path; + } + + // Previous versions converted the partition value to a path *twice*, + // so if the file resulting from that exists open it instead + NSString *encodedPartitionValue = [@(value.data()) + stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]]; + NSString *overEncodedRealmName = [[NSString alloc] initWithFormat:@"%@/%@", self.identifier, encodedPartitionValue]; + auto legacyPath = _user->sync_manager()->path_for_realm(config, std::string(overEncodedRealmName.UTF8String)); + if ([NSFileManager.defaultManager fileExistsAtPath:@(legacyPath.c_str())]) { + return legacyPath; + } + + return path; +} + +- (std::string)pathForFlexibleSync { + if (!_user) { + @throw RLMException(@"This is an exceptional state, `RLMUser` cannot be initialised without a reference to `SyncUser`"); + } + + SyncConfig config(_user, SyncConfig::FLXSyncEnabled{}); + return _user->sync_manager()->path_for_realm(config, realm::none); +} + +- (nullable RLMSyncSession *)sessionForPartitionValue:(id)partitionValue { + if (!_user) { + return nil; + } + + std::stringstream s; + s << RLMConvertRLMBSONToBson(partitionValue); + auto path = [self pathForPartitionValue:s.str()]; + if (auto session = _user->session_for_on_disk_path(path)) { + return [[RLMSyncSession alloc] initWithSyncSession:session]; + } + return nil; +} + +- (NSArray *)allSessions { + if (!_user) { + return @[]; + } + NSMutableArray *buffer = [NSMutableArray array]; + auto sessions = _user->all_sessions(); + for (auto session : sessions) { + [buffer addObject:[[RLMSyncSession alloc] initWithSyncSession:std::move(session)]]; + } + return [buffer copy]; +} + +- (NSString *)identifier { + if (!_user) { + return @""; + } + return @(_user->identity().c_str()); +} + +- (NSArray *)identities { + if (!_user) { + return @[]; + } + NSMutableArray *buffer = [NSMutableArray array]; + auto identities = _user->identities(); + for (auto& identity : identities) { + [buffer addObject: [[RLMUserIdentity alloc] initUserIdentityWithProviderType:@(identity.provider_type.c_str()) + identifier:@(identity.id.c_str())]]; + } + + return [buffer copy]; +} + +- (RLMUserState)state { + if (!_user) { + return RLMUserStateRemoved; + } + switch (_user->state()) { + case SyncUser::State::LoggedIn: + return RLMUserStateLoggedIn; + case SyncUser::State::LoggedOut: + return RLMUserStateLoggedOut; + case SyncUser::State::Removed: + return RLMUserStateRemoved; + } +} + +- (void)refreshCustomDataWithCompletion:(RLMUserCustomDataBlock)completion { + _user->refresh_custom_data([completion, self](std::optional error) { + if (!error) { + return completion([self customData], nil); + } + + completion(nil, makeError(*error)); + }); +} + +- (void)linkUserWithCredentials:(RLMCredentials *)credentials + completion:(RLMOptionalUserBlock)completion { + _app._realmApp->link_user(_user, credentials.appCredentials, + ^(std::shared_ptr user, std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + + completion([[RLMUser alloc] initWithUser:user app:_app], nil); + }); +} + +- (void)removeWithCompletion:(RLMOptionalErrorBlock)completion { + _app._realmApp->remove_user(_user, ^(std::optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (void)deleteWithCompletion:(RLMUserOptionalErrorBlock)completion { + _app._realmApp->delete_user(_user, ^(std::optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (void)logOutWithCompletion:(RLMOptionalErrorBlock)completion { + _app._realmApp->log_out(_user, ^(std::optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (RLMAPIKeyAuth *)apiKeysAuth { + return [[RLMAPIKeyAuth alloc] initWithApp:_app]; +} + +- (RLMMongoClient *)mongoClientWithServiceName:(NSString *)serviceName { + return [[RLMMongoClient alloc] initWithUser:self serviceName:serviceName]; +} + +- (void)callFunctionNamed:(NSString *)name + arguments:(NSArray> *)arguments + completionBlock:(RLMCallFunctionCompletionBlock)completionBlock { + bson::BsonArray args; + + for (id argument in arguments) { + args.push_back(RLMConvertRLMBSONToBson(argument)); + } + + _app._realmApp->call_function(_user, name.UTF8String, args, + [completionBlock](std::optional&& response, + std::optional error) { + if (error) { + return completionBlock(nil, makeError(*error)); + } + + completionBlock(RLMConvertBsonToRLMBSON(*response), nil); + }); +} + +- (void)handleResponse:(std::optional)error + completion:(RLMOptionalErrorBlock)completion { + if (error) { + return completion(makeError(*error)); + } + completion(nil); +} + +#pragma mark - Private API + ++ (void)_setUpBindingContextFactory { + SyncUser::set_binding_context_factory([] { + return std::make_shared(); + }); +} + +- (NSString *)refreshToken { + if (!_user || _user->refresh_token().empty()) { + return nil; + } + return @(_user->refresh_token().c_str()); +} + +- (NSString *)accessToken { + if (!_user || _user->access_token().empty()) { + return nil; + } + return @(_user->access_token().c_str()); +} + +- (NSDictionary *)customData { + if (!_user || !_user->custom_data()) { + return @{}; + } + + return (NSDictionary *)RLMConvertBsonToRLMBSON(*_user->custom_data()); +} + +- (RLMUserProfile *)profile { + if (!_user) { + return [RLMUserProfile new]; + } + + return [[RLMUserProfile alloc] initWithUserProfile:_user->user_profile()]; +} +- (std::shared_ptr)_syncUser { + return _user; +} + +- (RLMUserSubscriptionToken *)subscribe:(RLMUserNotificationBlock)block { + return [[RLMUserSubscriptionToken alloc] initWithUser:_user token:_user->subscribe([block, self] (auto&) { + block(self); + })]; +} +@end + +#pragma mark - RLMUserIdentity + +@implementation RLMUserIdentity + +- (instancetype)initUserIdentityWithProviderType:(NSString *)providerType + identifier:(NSString *)identifier { + if (self = [super init]) { + _providerType = providerType; + _identifier = identifier; + } + return self; +} + +@end + +#pragma mark - RLMUserProfile + +@interface RLMUserProfile () { + SyncUserProfile _userProfile; +} +@end + +static NSString* userProfileMemberToNSString(const std::optional& member) { + if (member == util::none) { + return nil; + } + return @(member->c_str()); +} + +@implementation RLMUserProfile + +using UserProfileMember = std::optional (SyncUserProfile::*)() const; + +- (instancetype)initWithUserProfile:(SyncUserProfile)userProfile { + if (self = [super init]) { + _userProfile = std::move(userProfile); + } + return self; +} + +- (NSString *)name { + return userProfileMemberToNSString(_userProfile.name()); +} +- (NSString *)email { + return userProfileMemberToNSString(_userProfile.email()); +} +- (NSString *)pictureURL { + return userProfileMemberToNSString(_userProfile.picture_url()); +} +- (NSString *)firstName { + return userProfileMemberToNSString(_userProfile.first_name()); +} +- (NSString *)lastName { + return userProfileMemberToNSString(_userProfile.last_name());; +} +- (NSString *)gender { + return userProfileMemberToNSString(_userProfile.gender()); +} +- (NSString *)birthday { + return userProfileMemberToNSString(_userProfile.birthday()); +} +- (NSString *)minAge { + return userProfileMemberToNSString(_userProfile.min_age()); +} +- (NSString *)maxAge { + return userProfileMemberToNSString(_userProfile.max_age()); +} +- (NSDictionary *)metadata { + return (NSDictionary *)RLMConvertBsonToRLMBSON(_userProfile.data()); +} + +@end diff --git a/Pods/Realm/Realm/RLMUserAPIKey.mm b/Pods/Realm/Realm/RLMUserAPIKey.mm new file mode 100644 index 0000000..cce6e29 --- /dev/null +++ b/Pods/Realm/Realm/RLMUserAPIKey.mm @@ -0,0 +1,68 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMUserAPIKey.h" +#import "RLMUserAPIKey_Private.hpp" +#import "RLMUtil.hpp" +#import "RLMObjectId_Private.hpp" + +@interface RLMUserAPIKey() { + realm::app::App::UserAPIKey _userAPIKey; +} +@end + +@implementation RLMUserAPIKey + +- (instancetype)initWithUserAPIKey:(realm::app::App::UserAPIKey)userAPIKey { + if (self = [super init]) { + _userAPIKey = userAPIKey; + return self; + } + + return nil; +} + +// Indicates if the API key is disabled or not +- (BOOL)disabled { + return _userAPIKey.disabled; +} + +// The name of the key. +- (NSString *)name { + return @(_userAPIKey.name.c_str()); +} + +// The actual key. Will only be included in +// the response when an API key is first created. +- (NSString *)key { + if (_userAPIKey.key) { + return @(_userAPIKey.key->c_str()); + } + + return nil; +} + +- (RLMObjectId *)objectId { + return [[RLMObjectId alloc] initWithValue:_userAPIKey.id]; +} + +- (realm::app::App::UserAPIKey)_apiKey { + return _userAPIKey; +} + +@end diff --git a/Pods/Realm/Realm/RLMUtil.mm b/Pods/Realm/Realm/RLMUtil.mm new file mode 100644 index 0000000..d99e402 --- /dev/null +++ b/Pods/Realm/Realm/RLMUtil.mm @@ -0,0 +1,557 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMUtil.hpp" + +#import "RLMArray_Private.hpp" +#import "RLMAccessor.hpp" +#import "RLMDecimal128_Private.hpp" +#import "RLMDictionary_Private.h" +#import "RLMError_Private.hpp" +#import "RLMObjectId_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMProperty_Private.h" +#import "RLMSwiftValueStorage.h" +#import "RLMSchema_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftCollectionBase.h" +#import "RLMSwiftSupport.h" +#import "RLMUUID_Private.hpp" +#import "RLMValue.h" + +#import +#import + +#include +#include + +#if !defined(REALM_COCOA_VERSION) +#import "RLMVersion.h" +#endif + +static inline RLMArray *asRLMArray(__unsafe_unretained id const value) { + return RLMDynamicCast(value) ?: RLMDynamicCast(value)._rlmCollection; +} + +static inline RLMSet *asRLMSet(__unsafe_unretained id const value) { + return RLMDynamicCast(value) ?: RLMDynamicCast(value)._rlmCollection; +} + +static inline RLMDictionary *asRLMDictionary(__unsafe_unretained id const value) { + return RLMDynamicCast(value) ?: RLMDynamicCast(value)._rlmCollection; +} + +static inline bool checkCollectionType(__unsafe_unretained id const collection, + RLMPropertyType type, + bool optional, + __unsafe_unretained NSString *const objectClassName) { + return collection.type == type && collection.optional == optional + && (type != RLMPropertyTypeObject || [collection.objectClassName isEqualToString:objectClassName]); +} + +static id (*s_bridgeValue)(id); +id RLMAsFastEnumeration(__unsafe_unretained id obj) { + if (!obj) { + return nil; + } + if ([obj conformsToProtocol:@protocol(NSFastEnumeration)]) { + return obj; + } + if (s_bridgeValue) { + id bridged = s_bridgeValue(obj); + if ([bridged conformsToProtocol:@protocol(NSFastEnumeration)]) { + return bridged; + } + } + return nil; +} + +void RLMSetSwiftBridgeCallback(id (*callback)(id)) { + s_bridgeValue = callback; +} + +id RLMBridgeSwiftValue(__unsafe_unretained id value) { + if (!value || !s_bridgeValue) { + return nil; + } + return s_bridgeValue(value); +} + +bool RLMIsSwiftObjectClass(Class cls) { + return [cls isSubclassOfClass:RealmSwiftObject.class] + || [cls isSubclassOfClass:RealmSwiftEmbeddedObject.class]; +} + +static BOOL validateValue(__unsafe_unretained id const value, + RLMPropertyType type, + bool optional, + bool collection, + __unsafe_unretained NSString *const objectClassName) { + if (optional && !RLMCoerceToNil(value)) { + return YES; + } + + if (collection) { + if (auto rlmArray = asRLMArray(value)) { + return checkCollectionType(rlmArray, type, optional, objectClassName); + } + else if (auto rlmSet = asRLMSet(value)) { + return checkCollectionType(rlmSet, type, optional, objectClassName); + } + else if (auto rlmDictionary = asRLMDictionary(value)) { + return checkCollectionType(rlmDictionary, type, optional, objectClassName); + } + if (id enumeration = RLMAsFastEnumeration(value)) { + // check each element for compliance + for (id el in enumeration) { + if (!RLMValidateValue(el, type, optional, false, objectClassName)) { + return NO; + } + } + return YES; + } + if (!value || value == NSNull.null) { + return YES; + } + return NO; + } + + switch (type) { + case RLMPropertyTypeString: + return [value isKindOfClass:[NSString class]]; + case RLMPropertyTypeBool: + if ([value isKindOfClass:[NSNumber class]]) { + return numberIsBool(value); + } + return NO; + case RLMPropertyTypeDate: + return [value isKindOfClass:[NSDate class]]; + case RLMPropertyTypeInt: + if (NSNumber *number = RLMDynamicCast(value)) { + return numberIsInteger(number); + } + return NO; + case RLMPropertyTypeFloat: + if (NSNumber *number = RLMDynamicCast(value)) { + return numberIsFloat(number); + } + return NO; + case RLMPropertyTypeDouble: + if (NSNumber *number = RLMDynamicCast(value)) { + return numberIsDouble(number); + } + return NO; + case RLMPropertyTypeData: + return [value isKindOfClass:[NSData class]]; + case RLMPropertyTypeAny: { + return !value + || [value conformsToProtocol:@protocol(RLMValue)]; + } + case RLMPropertyTypeLinkingObjects: + return YES; + case RLMPropertyTypeObject: { + // only NSNull, nil, or objects which derive from RLMObject and match the given + // object class are valid + RLMObjectBase *objBase = RLMDynamicCast(value); + return objBase && [objBase->_objectSchema.className isEqualToString:objectClassName]; + } + case RLMPropertyTypeObjectId: + return [value isKindOfClass:[RLMObjectId class]]; + case RLMPropertyTypeDecimal128: + return [value isKindOfClass:[NSNumber class]] + || [value isKindOfClass:[RLMDecimal128 class]] + || ([value isKindOfClass:[NSString class]] && realm::Decimal128::is_valid_str([value UTF8String])); + case RLMPropertyTypeUUID: + return [value isKindOfClass:[NSUUID class]] + || ([value isKindOfClass:[NSString class]] && realm::UUID::is_valid_string([value UTF8String])); + } + @throw RLMException(@"Invalid RLMPropertyType specified"); +} + +id RLMValidateValue(__unsafe_unretained id const value, + RLMPropertyType type, bool optional, bool collection, + __unsafe_unretained NSString *const objectClassName) { + if (validateValue(value, type, optional, collection, objectClassName)) { + return value ?: NSNull.null; + } + if (id bridged = RLMBridgeSwiftValue(value)) { + if (validateValue(bridged, type, optional, collection, objectClassName)) { + return bridged ?: NSNull.null; + } + } + return nil; + } + + +void RLMThrowTypeError(__unsafe_unretained id const obj, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained RLMProperty *const prop) { + @throw RLMException(@"Invalid value '%@' of type '%@' for '%@%s'%s property '%@.%@'.", + obj, [obj class], + prop.objectClassName ?: RLMTypeToString(prop.type), prop.optional ? "?" : "", + prop.array ? " array" : prop.set ? " set" : prop.dictionary ? " dictionary" : "", objectSchema.className, prop.name); +} + +void RLMValidateValueForProperty(__unsafe_unretained id const obj, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained RLMProperty *const prop, + bool validateObjects) { + // This duplicates a lot of the checks in RLMIsObjectValidForProperty() + // for the sake of more specific error messages + if (prop.collection) { + // nil is considered equivalent to an empty array for historical reasons + // since we don't support null arrays (only arrays containing null), + // it's not worth the BC break to change this + if (!obj || obj == NSNull.null) { + return; + } + id enumeration = RLMAsFastEnumeration(obj); + if (!enumeration) { + @throw RLMException(@"Invalid value (%@) for '%@%s' %@ property '%@.%@': value is not enumerable.", + obj, + prop.objectClassName ?: RLMTypeToString(prop.type), + prop.optional ? "?" : "", + prop.array ? @"array" : @"set", + objectSchema.className, prop.name); + } + if (!validateObjects && prop.type == RLMPropertyTypeObject) { + return; + } + + if (RLMArray *array = asRLMArray(obj)) { + if (!checkCollectionType(array, prop.type, prop.optional, prop.objectClassName)) { + @throw RLMException(@"RLMArray<%@%s> does not match expected type '%@%s' for property '%@.%@'.", + array.objectClassName ?: RLMTypeToString(array.type), array.optional ? "?" : "", + prop.objectClassName ?: RLMTypeToString(prop.type), prop.optional ? "?" : "", + objectSchema.className, prop.name); + } + return; + } + else if (RLMSet *set = asRLMSet(obj)) { + if (!checkCollectionType(set, prop.type, prop.optional, prop.objectClassName)) { + @throw RLMException(@"RLMSet<%@%s> does not match expected type '%@%s' for property '%@.%@'.", + set.objectClassName ?: RLMTypeToString(set.type), set.optional ? "?" : "", + prop.objectClassName ?: RLMTypeToString(prop.type), prop.optional ? "?" : "", + objectSchema.className, prop.name); + } + return; + } + else if (RLMDictionary *dictionary = asRLMDictionary(obj)) { + if (!checkCollectionType(dictionary, prop.type, prop.optional, prop.objectClassName)) { + @throw RLMException(@"RLMDictionary<%@, %@%s> does not match expected type '%@%s' for property '%@.%@'.", + RLMTypeToString(dictionary.keyType), + dictionary.objectClassName ?: RLMTypeToString(dictionary.type), dictionary.optional ? "?" : "", + prop.objectClassName ?: RLMTypeToString(prop.type), prop.optional ? "?" : "", + objectSchema.className, prop.name); + } + return; + } + + if (prop.dictionary) { + for (id key in enumeration) { + id value = enumeration[key]; + if (!RLMValidateValue(value, prop.type, prop.optional, false, prop.objectClassName)) { + RLMThrowTypeError(value, objectSchema, prop); + } + } + } + else { + for (id value in enumeration) { + if (!RLMValidateValue(value, prop.type, prop.optional, false, prop.objectClassName)) { + RLMThrowTypeError(value, objectSchema, prop); + } + } + } + return; + } + + // For create() we want to skip the validation logic for objects because + // we allow much fuzzier matching (any KVC-compatible object with at least + // all the non-defaulted fields), and all the logic for that lives in the + // object store rather than here + if (prop.type == RLMPropertyTypeObject && !validateObjects) { + return; + } + if (RLMIsObjectValidForProperty(obj, prop)) { + return; + } + + RLMThrowTypeError(obj, objectSchema, prop); +} + +BOOL RLMIsObjectValidForProperty(__unsafe_unretained id const obj, + __unsafe_unretained RLMProperty *const property) { + return RLMValidateValue(obj, property.type, property.optional, property.collection, property.objectClassName) != nil; +} + +NSDictionary *RLMDefaultValuesForObjectSchema(__unsafe_unretained RLMObjectSchema *const objectSchema) { + if (!objectSchema.isSwiftClass) { + return [objectSchema.objectClass defaultPropertyValues]; + } + + NSMutableDictionary *defaults = nil; + if ([objectSchema.objectClass isSubclassOfClass:RLMObject.class]) { + defaults = [NSMutableDictionary dictionaryWithDictionary:[objectSchema.objectClass defaultPropertyValues]]; + } + else { + defaults = [NSMutableDictionary dictionary]; + } + RLMObject *defaultObject = [[objectSchema.objectClass alloc] init]; + for (RLMProperty *prop in objectSchema.properties) { + if (!defaults[prop.name] && defaultObject[prop.name]) { + defaults[prop.name] = defaultObject[prop.name]; + } + } + return defaults; +} + +static NSException *RLMException(NSString *reason, NSDictionary *additionalUserInfo) { + NSMutableDictionary *userInfo = @{RLMRealmVersionKey: REALM_COCOA_VERSION, + RLMRealmCoreVersionKey: @REALM_VERSION}.mutableCopy; + if (additionalUserInfo != nil) { + [userInfo addEntriesFromDictionary:additionalUserInfo]; + } + NSException *e = [NSException exceptionWithName:RLMExceptionName + reason:reason + userInfo:userInfo]; + return e; +} + +NSException *RLMException(NSString *fmt, ...) { + va_list args; + va_start(args, fmt); + NSException *e = RLMException([[NSString alloc] initWithFormat:fmt arguments:args], @{}); + va_end(args); + return e; +} + +NSException *RLMException(std::exception const& exception) { + return RLMException(@"%s", exception.what()); +} + +NSException *RLMException(realm::Exception const& exception) { + return RLMException(@(exception.what()), + @{@"Error Code": @(exception.code()), + @"Underlying": makeError(exception.to_status())}); +} + +void RLMSetErrorOrThrow(NSError *error, NSError **outError) { + if (outError) { + *outError = error; + } + else { + @throw RLMException(error.localizedDescription, @{NSUnderlyingErrorKey: error}); + } +} + +BOOL RLMIsDebuggerAttached() +{ + int name[] = { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID, + getpid() + }; + + struct kinfo_proc info; + size_t info_size = sizeof(info); + if (sysctl(name, sizeof(name)/sizeof(name[0]), &info, &info_size, NULL, 0) == -1) { + NSLog(@"sysctl() failed: %s", strerror(errno)); + return false; + } + + return (info.kp_proc.p_flag & P_TRACED) != 0; +} + +BOOL RLMIsRunningInPlayground() { + return [[NSBundle mainBundle].bundleIdentifier hasPrefix:@"com.apple.dt.playground."]; +} + +realm::Mixed RLMObjcToMixed(__unsafe_unretained id const value, + __unsafe_unretained RLMRealm *const realm, + realm::CreatePolicy createPolicy) { + if (!value || value == NSNull.null) { + return realm::Mixed(); + } + id v; + if ([value conformsToProtocol:@protocol(RLMValue)]) { + v = value; + } + else { + v = RLMBridgeSwiftValue(value); + if (v == NSNull.null) { + return realm::Mixed(); + } + REALM_ASSERT([v conformsToProtocol:@protocol(RLMValue)]); + } + + RLMPropertyType type = [v rlm_valueType]; + return switch_on_type(static_cast(type), realm::util::overload{[&](realm::Obj*) { + // The RLMObjectBase may be unmanaged and therefor has no RLMClassInfo attached. + // So we fetch from the Realm instead. + // If the Object is managed use it's RLMClassInfo instead so we do not have to do a + // lookup in the table of schemas. + RLMObjectBase *objBase = v; + RLMAccessorContext c{objBase->_info ? *objBase->_info : realm->_info[objBase->_objectSchema.className]}; + auto obj = c.unbox(v, createPolicy); + return obj.is_valid() ? realm::Mixed(obj) : realm::Mixed(); + }, [&](auto t) { + RLMStatelessAccessorContext c; + return realm::Mixed(c.unbox>(v)); + }, [&](realm::Mixed*) -> realm::Mixed { + REALM_UNREACHABLE(); + }}); +} + +id RLMMixedToObjc(realm::Mixed const& mixed, + __unsafe_unretained RLMRealm *realm, + RLMClassInfo *classInfo) { + if (mixed.is_null()) { + return NSNull.null; + } + switch (mixed.get_type()) { + case realm::type_String: + return RLMStringDataToNSString(mixed.get_string()); + case realm::type_Int: + return @(mixed.get_int()); + case realm::type_Float: + return @(mixed.get_float()); + case realm::type_Double: + return @(mixed.get_double()); + case realm::type_Bool: + return @(mixed.get_bool()); + case realm::type_Timestamp: + return RLMTimestampToNSDate(mixed.get_timestamp()); + case realm::type_Binary: + return RLMBinaryDataToNSData(mixed.get()); + case realm::type_Decimal: + return [[RLMDecimal128 alloc] initWithDecimal128:mixed.get()]; + case realm::type_ObjectId: + return [[RLMObjectId alloc] initWithValue:mixed.get()]; + case realm::type_TypedLink: + return RLMObjectFromObjLink(realm, mixed.get(), classInfo->isSwiftClass()); + case realm::type_Link: { + auto obj = classInfo->table()->get_object((mixed).get()); + return RLMCreateObjectAccessor(*classInfo, std::move(obj)); + } + case realm::type_UUID: + return [[NSUUID alloc] initWithRealmUUID:mixed.get()]; + case realm::type_LinkList: + REALM_UNREACHABLE(); + default: + @throw RLMException(@"Invalid data type for RLMPropertyTypeAny property."); + } +} + +realm::UUID RLMObjcToUUID(__unsafe_unretained id const value) { + try { + if (auto uuid = RLMDynamicCast(value)) { + return uuid.rlm_uuidValue; + } + if (auto string = RLMDynamicCast(value)) { + return realm::UUID(string.UTF8String); + } + } + catch (std::exception const& e) { + @throw RLMException(@"Cannot convert value '%@' of type '%@' to uuid: %s", + value, [value class], e.what()); + } + @throw RLMException(@"Cannot convert value '%@' of type '%@' to uuid", value, [value class]); +} + +realm::Decimal128 RLMObjcToDecimal128(__unsafe_unretained id const value) { + try { + if (!value || value == NSNull.null) { + return realm::Decimal128(realm::null()); + } + if (auto decimal = RLMDynamicCast(value)) { + return decimal.decimal128Value; + } + if (auto string = RLMDynamicCast(value)) { + return realm::Decimal128(string.UTF8String); + } + if (auto decimal = RLMDynamicCast(value)) { + return realm::Decimal128(decimal.stringValue.UTF8String); + } + if (auto number = RLMDynamicCast(value)) { + auto type = number.objCType[0]; + if (type == *@encode(double) || type == *@encode(float)) { + return realm::Decimal128(number.doubleValue); + } + else if (std::isupper(type)) { + return realm::Decimal128(number.unsignedLongLongValue); + } + else { + return realm::Decimal128(number.longLongValue); + } + } + if (id bridged = RLMBridgeSwiftValue(value); bridged != value) { + return RLMObjcToDecimal128(bridged); + } + } + catch (std::exception const& e) { + @throw RLMException(@"Cannot convert value '%@' of type '%@' to decimal128: %s", + value, [value class], e.what()); + } + @throw RLMException(@"Cannot convert value '%@' of type '%@' to decimal128", value, [value class]); +} + +NSString *RLMDefaultDirectoryForBundleIdentifier(NSString *bundleIdentifier) { +#if TARGET_OS_TV + (void)bundleIdentifier; + // tvOS prohibits writing to the Documents directory, so we use the Library/Caches directory instead. + return NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; +#elif TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST + (void)bundleIdentifier; + // On iOS the Documents directory isn't user-visible, so put files there + return NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; +#else + // On OS X it is, so put files in Application Support. If we aren't running + // in a sandbox, put it in a subdirectory based on the bundle identifier + // to avoid accidentally sharing files between applications + NSString *path = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)[0]; + if (![[NSProcessInfo processInfo] environment][@"APP_SANDBOX_CONTAINER_ID"]) { + if (!bundleIdentifier) { + bundleIdentifier = [NSBundle mainBundle].bundleIdentifier; + } + if (!bundleIdentifier) { + bundleIdentifier = [NSBundle mainBundle].executablePath.lastPathComponent; + } + + path = [path stringByAppendingPathComponent:bundleIdentifier]; + + // create directory + [[NSFileManager defaultManager] createDirectoryAtPath:path + withIntermediateDirectories:YES + attributes:nil + error:nil]; + } + return path; +#endif +} + +NSDateFormatter *RLMISO8601Formatter() { + // note: NSISO8601DateFormatter can't be used as it doesn't support milliseconds + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; + dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + dateFormatter.calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian]; + return dateFormatter; +} diff --git a/Pods/Realm/Realm/RLMValue.mm b/Pods/Realm/Realm/RLMValue.mm new file mode 100644 index 0000000..ec36455 --- /dev/null +++ b/Pods/Realm/Realm/RLMValue.mm @@ -0,0 +1,124 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMValue.h" +#import "RLMUtil.hpp" + +#pragma mark NSData + +@implementation NSData (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeData; +} + +@end + +#pragma mark NSDate + +@implementation NSDate (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeDate; +} + +@end + +#pragma mark NSNumber + +@implementation NSNumber (RLMValue) + +- (RLMPropertyType)rlm_valueType { + if ([self objCType][0] == 'c' && (self.intValue == 0 || self.intValue == 1)) { + return RLMPropertyTypeBool; + } + else if (numberIsInteger(self)) { + return RLMPropertyTypeInt; + } + else if (*@encode(float) == [self objCType][0]) { + return RLMPropertyTypeFloat; + } + else if (*@encode(double) == [self objCType][0]) { + return RLMPropertyTypeDouble; + } + else { + @throw RLMException(@"Unknown numeric type on type RLMValue."); + } +} + +@end + +#pragma mark NSNull + +@implementation NSNull (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeAny; +} + +@end + +#pragma mark NSString + +@implementation NSString (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeString; +} + +@end + +#pragma mark NSUUID + +@implementation NSUUID (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeUUID; +} + +@end + +#pragma mark RLMDecimal128 + +@implementation RLMDecimal128 (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeDecimal128; +} + +@end + +#pragma mark RLMObjectBase + +@implementation RLMObjectBase (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeObject; +} + +@end + +#pragma mark RLMObjectId + +@implementation RLMObjectId (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeObjectId; +} + +@end diff --git a/Pods/Realm/Realm/Realm.modulemap b/Pods/Realm/Realm/Realm.modulemap new file mode 100644 index 0000000..519ddc2 --- /dev/null +++ b/Pods/Realm/Realm/Realm.modulemap @@ -0,0 +1,88 @@ +framework module Realm { + export Foundation + + umbrella header "Realm.h" + + header "RLMArray.h" + header "RLMAsymmetricObject.h" + header "RLMDecimal128.h" + header "RLMDictionary.h" + header "RLMEmbeddedObject.h" + header "RLMLogger.h" + header "RLMMigration.h" + header "RLMObject.h" + header "RLMObjectId.h" + header "RLMObjectSchema.h" + header "RLMProperty.h" + header "RLMProviderClient.h" + header "RLMRealm+Sync.h" + header "RLMRealm.h" + header "RLMRealmConfiguration.h" + header "RLMResults.h" + header "RLMSchema.h" + header "RLMSectionedResults.h" + header "RLMSet.h" + header "RLMValue.h" + + header "RLMApp.h" + header "RLMCredentials.h" + header "RLMNetworkTransport.h" + header "RLMPushClient.h" + header "RLMRealm+Sync.h" + header "RLMSyncConfiguration.h" + header "RLMSyncManager.h" + header "RLMSyncSession.h" + header "RLMUser.h" + header "RLMUserAPIKey.h" + header "RLMAPIKeyAuth.h" + header "RLMEmailPasswordAuth.h" + header "NSError+RLMSync.h" + header "RLMBSON.h" + header "RLMMongoClient.h" + header "RLMMongoDatabase.h" + header "RLMMongoCollection.h" + header "RLMUpdateResult.h" + header "RLMFindOptions.h" + header "RLMFindOneAndModifyOptions.h" + header "RLMSyncSubscription.h" + + explicit module Private { + header "RLMAccessor.h" + header "RLMApp_Private.h" + header "RLMArray_Private.h" + header "RLMAsyncTask_Private.h" + header "RLMCollection_Private.h" + header "RLMDictionary_Private.h" + header "RLMLogger_Private.h" + header "RLMEvent.h" + header "RLMMongoCollection_Private.h" + header "RLMObjectBase_Dynamic.h" + header "RLMObjectBase_Private.h" + header "RLMObjectSchema_Private.h" + header "RLMObjectStore.h" + header "RLMObject_Private.h" + header "RLMProperty_Private.h" + header "RLMRealmConfiguration_Private.h" + header "RLMRealm_Private.h" + header "RLMResults_Private.h" + header "RLMScheduler.h" + header "RLMSchema_Private.h" + header "RLMSectionedResults.h" + header "RLMSet_Private.h" + header "RLMSwiftCollectionBase.h" + header "RLMSwiftProperty.h" + header "RLMSwiftValueStorage.h" + header "RLMSyncConfiguration_Private.h" + header "RLMSyncSubscription_Private.h" + header "RLMUser_Private.h" + } + + explicit module Dynamic { + header "RLMRealm_Dynamic.h" + header "RLMObjectBase_Dynamic.h" + } + + explicit module Swift { + header "RLMSwiftObject.h" + } +} diff --git a/Pods/Realm/core/realm-monorepo.xcframework/Info.plist b/Pods/Realm/core/realm-monorepo.xcframework/Info.plist new file mode 100644 index 0000000..d911db7 --- /dev/null +++ b/Pods/Realm/core/realm-monorepo.xcframework/Info.plist @@ -0,0 +1,152 @@ + + + + + AvailableLibraries + + + HeadersPath + Headers + LibraryIdentifier + macos-x86_64_arm64 + LibraryPath + librealm-monorepo.a + SupportedArchitectures + x86_64 +arm64 + SupportedPlatform + macos + + + HeadersPath + Headers + LibraryIdentifier + ios-arm64 + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 + SupportedPlatform + ios + + + HeadersPath + Headers + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 +x86_64 + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + HeadersPath + Headers + LibraryIdentifier + ios-arm64_x86_64-maccatalyst + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 +x86_64 + SupportedPlatform + ios + SupportedPlatformVariant + maccatalyst + + + HeadersPath + Headers + LibraryIdentifier + watchos-arm64_armv7k_arm64_32 + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 +armv7k +arm64_32 + SupportedPlatform + watchos + + + HeadersPath + Headers + LibraryIdentifier + watchos-arm64_i386_x86_64-simulator + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 +i386 +x86_64 + SupportedPlatform + watchos + SupportedPlatformVariant + simulator + + + HeadersPath + Headers + LibraryIdentifier + tvos-arm64 + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 + SupportedPlatform + tvos + + + HeadersPath + Headers + LibraryIdentifier + tvos-arm64_x86_64-simulator + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 +x86_64 + SupportedPlatform + tvos + SupportedPlatformVariant + simulator + + + HeadersPath + Headers + LibraryIdentifier + xros-arm64 + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 + SupportedPlatform + xros + + + HeadersPath + Headers + LibraryIdentifier + xros-arm64_x86_64-simulator + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 +x86_64 + SupportedPlatform + xros + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Pods/Realm/core/realm-monorepo.xcframework/ios-arm64/Headers/external/json/json.hpp b/Pods/Realm/core/realm-monorepo.xcframework/ios-arm64/Headers/external/json/json.hpp new file mode 100644 index 0000000..77bd173 --- /dev/null +++ b/Pods/Realm/core/realm-monorepo.xcframework/ios-arm64/Headers/external/json/json.hpp @@ -0,0 +1,22875 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.7.3 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 7 +#define NLOHMANN_JSON_VERSION_PATCH 3 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include + + +#include + +// #include + + +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +// #include + + +#include // size_t + +namespace nlohmann +{ +namespace detail +{ +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // pair +// #include +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to + * the public domain worldwide. This software is distributed without + * any warranty. + * + * For details, see . + * SPDX-License-Identifier: CC0-1.0 + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 11) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 11 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(_MSC_VER) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(__COMPCERT__) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) && JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +#else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif JSON_HEDLEY_TI_VERSION_CHECK(8,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,3,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(__cplusplus) && (__cplusplus >= 201703L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_UNREACHABLE() __assume(0) +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_UNREACHABLE() std::_nassert(0) + #else + #define JSON_HEDLEY_UNREACHABLE() _nassert(0) + #endif + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value +#elif defined(EXIT_FAILURE) + #define JSON_HEDLEY_UNREACHABLE() abort() +#else + #define JSON_HEDLEY_UNREACHABLE() + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() +#endif + +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#elif \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(JSON_HEDLEY_ARM_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) + #define JSON_HEDLEY_ASSUME(expr) ((void) ((expr) ? 1 : (__builtin_unreachable(), 1))) +#else + #define JSON_HEDLEY_ASSUME(expr) ((void) (expr)) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr)) +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(expr, value, probability) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, probability) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, probability) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#if !defined(JSON_HEDLEY_BUILTIN_UNPREDICTABLE) + #define JSON_HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5) +#endif +#elif \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void) (expected)), !!(expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (((void) (expected)), !!(expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else + #define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) + #define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif JSON_HEDLEY_TI_VERSION_CHECK(7,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else + #define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) + #define JSON_HEDLEY_PRIVATE + #define JSON_HEDLEY_PUBLIC __declspec(dllexport) + #define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else + #if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) + #define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) + #else + #define JSON_HEDLEY_PRIVATE + #define JSON_HEDLEY_PUBLIC + #endif + #define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(JSON_HEDLEY_SUNPRO_VERSION) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + JSON_HEDLEY_HAS_FEATURE(c_static_assert) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ + (defined(__cplusplus) && JSON_HEDLEY_TI_VERSION_CHECK(8,3,0)) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (*((T*) &(expr))) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_CPP_CAST(T, expr) static_cast(expr) +#else + #define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + JSON_HEDLEY_RETURNS_NON_NULL + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + JSON_HEDLEY_NON_NULL(3) + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. +json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] pos the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, const position_t& pos, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + position_string(pos) + ": " + what_arg; + return parse_error(id_, pos.chars_read_total, w.c_str()); + } + + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} + + static std::string position_string(const position_t& pos) + { + return " at line " + std::to_string(pos.lines_read + 1) + + ", column " + std::to_string(pos.chars_read_current_line); + } +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | +json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. | +json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | +json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // not +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // not +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + + +#include // random_access_iterator_tag + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include + +// #include + + +// https://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template