diff --git a/.github/workflows/xcodebuild.yml b/.github/workflows/xcodebuild.yml index 8a61b32d..29f5de15 100644 --- a/.github/workflows/xcodebuild.yml +++ b/.github/workflows/xcodebuild.yml @@ -10,27 +10,13 @@ on: branches: - '**' -env: - # Customize the Xcode configuration here (Release or Debug) - # NOTE: If we decide to archive the build products we should build with RelWithDebInfo instead. - CONFIGURATION: Debug - jobs: build: runs-on: macOS-latest - steps: - uses: actions/checkout@v2 with: submodules: recursive - -#### BUILD - - name: "Build Tests" - uses: sersoft-gmbh/xcodebuild-action@v1 - with: - project: CBL_C.xcodeproj - scheme: CBL_Tests - destination: platform=macOS - configuration: $CONFIGURATION - action: build + run: | + xcodebuild build -project CBL_C.xcodeproj -configuration "Debug" -scheme "CBL_Tests" -destination "platform=macOS" | xcpretty diff --git a/.gitignore b/.gitignore index b7b4072f..510339b7 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ python/CouchbaseLite/*.c Cargo.lock bindings/rust/CouchbaseLite/target/ build_apple_out + +# macOS +.DS_Store diff --git a/CBL_C.xcodeproj/project.pbxproj b/CBL_C.xcodeproj/project.pbxproj index d8bc7db8..4394ff56 100644 --- a/CBL_C.xcodeproj/project.pbxproj +++ b/CBL_C.xcodeproj/project.pbxproj @@ -85,19 +85,21 @@ 27DBD098246C9DE7002FD7A7 /* CBLDatabase+Apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = 27DBD097246C9DE7002FD7A7 /* CBLDatabase+Apple.mm */; }; 27DBD09C246CA60E002FD7A7 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 271A98AF243FDF55008C032D /* SystemConfiguration.framework */; }; 27DBD0A9246CA667002FD7A7 /* CBLLog.h in Headers */ = {isa = PBXBuildFile; fileRef = 277B77C6245B44BE00B222D3 /* CBLLog.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 40EBC24F298D89CE00182F16 /* CBLUserAgent.hh in Headers */ = {isa = PBXBuildFile; fileRef = 40EBC23E298D896D00182F16 /* CBLUserAgent.hh */; }; + 40EBC260298D8A9900182F16 /* CBLUserAgent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 40EBC252298D8A9900182F16 /* CBLUserAgent.mm */; }; 6938073022DE96C200727053 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 277CC9B122BC4E2E00B245CB /* Security.framework */; }; 932062DB26BC6B43006917A5 /* CBLQuery.cc in Sources */ = {isa = PBXBuildFile; fileRef = 932062DA26BC6B43006917A5 /* CBLQuery.cc */; }; 9320630F26BDB408006917A5 /* CBLPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = 9320630126BDB340006917A5 /* CBLPlatform.h */; }; 9320631026BDB409006917A5 /* CBLPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = 9320630126BDB340006917A5 /* CBLPlatform.h */; settings = {ATTRIBUTES = (Public, ); }; }; 93965A6326A7CD50008728EE /* LogTest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 93965A6226A7CD50008728EE /* LogTest.cc */; }; 93965A6426A7CD50008728EE /* LogTest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 93965A6226A7CD50008728EE /* LogTest.cc */; }; - 93C70D3426D01B5A0093E927 /* BlobTest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 93C70D3326D01B5A0093E927 /* BlobTest.cc */; }; - 93C70D3526D01B5A0093E927 /* BlobTest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 93C70D3326D01B5A0093E927 /* BlobTest.cc */; }; 93C70CE026C4D3F80093E927 /* CBLEncryptable.h in Headers */ = {isa = PBXBuildFile; fileRef = 93C70CD226C4D3F20093E927 /* CBLEncryptable.h */; }; 93C70CE126C4D3F90093E927 /* CBLEncryptable.h in Headers */ = {isa = PBXBuildFile; fileRef = 93C70CD226C4D3F20093E927 /* CBLEncryptable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 93C70CE326C5B4BC0093E927 /* CBLEncryptable_CAPI.cc in Sources */ = {isa = PBXBuildFile; fileRef = 93C70CE226C5B4BC0093E927 /* CBLEncryptable_CAPI.cc */; }; 93C70D1726CB334D0093E927 /* ReplicatorPropEncTest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 93C70D1626CB334D0093E927 /* ReplicatorPropEncTest.cc */; }; 93C70D1826CB535D0093E927 /* ReplicatorPropEncTest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 93C70D1626CB334D0093E927 /* ReplicatorPropEncTest.cc */; }; + 93C70D3426D01B5A0093E927 /* BlobTest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 93C70D3326D01B5A0093E927 /* BlobTest.cc */; }; + 93C70D3526D01B5A0093E927 /* BlobTest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 93C70D3326D01B5A0093E927 /* BlobTest.cc */; }; 93EC366226C49AF700182B02 /* CBLEncryptable_Internal.hh in Headers */ = {isa = PBXBuildFile; fileRef = 93EC365D26C498AB00182B02 /* CBLEncryptable_Internal.hh */; }; /* End PBXBuildFile section */ @@ -207,13 +209,6 @@ remoteGlobalIDString = 27B61D6F21D6B64A0027CCDB; remoteInfo = "CBL_C Dylib"; }; - 2779ED5522E2881B0026ACD0 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 271C2A1B21CAC8920045856E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 27B61D6F21D6B64A0027CCDB; - remoteInfo = "CBL_C Dylib"; - }; 277CC9A522BC23DF00B245CB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 271C2A3821CAD5950045856E /* LiteCore.xcodeproj */; @@ -320,9 +315,6 @@ 275FA3342236E54D001C392D /* CBLPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CBLPrivate.h; sourceTree = ""; }; 276633A52602815000B9BD36 /* CBLDatabase_CAPI.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CBLDatabase_CAPI.cc; sourceTree = ""; }; 276634182605338300B9BD36 /* CBLDocument_CAPI.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CBLDocument_CAPI.cc; sourceTree = ""; }; - 2779ED2722DE83A60026ACD0 /* Blob.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = Blob.py; sourceTree = ""; }; - 2779ED3622DE83A60026ACD0 /* Collections.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = Collections.py; sourceTree = ""; }; - 2779ED5022E2493F0026ACD0 /* build_python.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = build_python.sh; path = Xcode/build_python.sh; sourceTree = SOURCE_ROOT; }; 277B77C6245B44BE00B222D3 /* CBLLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CBLLog.h; sourceTree = ""; }; 277B77D4245B44E900B222D3 /* CBLLog.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CBLLog.cc; sourceTree = ""; }; 277CC99422BC23DE00B245CB /* ReplicatorTest.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ReplicatorTest.cc; sourceTree = ""; }; @@ -365,13 +357,7 @@ 27B61DC321DEE1C20027CCDB /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; 27B61DD421DEE5DC0027CCDB /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; 27B61DD821DEEC540027CCDB /* Database.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Database.hh; sourceTree = ""; }; - 27C9B5BA21F12C970040BC45 /* test.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = test.py; path = test/test.py; sourceTree = ""; }; - 27C9B5BF21F12C970040BC45 /* BuildPyCBL.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = BuildPyCBL.py; path = ../BuildPyCBL.py; sourceTree = ""; }; - 27C9B5C021F12C970040BC45 /* Database.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = Database.py; sourceTree = ""; }; - 27C9B5C321F12C970040BC45 /* common.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = common.py; sourceTree = ""; }; - 27C9B5C421F12C970040BC45 /* Document.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = Document.py; sourceTree = ""; }; 27C9B5DB21F296C10040BC45 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - 27C9B5DC21F29D500040BC45 /* Query.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = Query.py; sourceTree = ""; }; 27C9B5E021F655110040BC45 /* CBLDatabase_Internal.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CBLDatabase_Internal.hh; sourceTree = ""; }; 27C9B5F121F7D74A0040BC45 /* Replicator.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Replicator.hh; sourceTree = ""; }; 27C9B5F221F7EE670040BC45 /* CBLTest.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = CBLTest.c; sourceTree = ""; }; @@ -385,15 +371,18 @@ 27DBCF41246B81EE002FD7A7 /* LibC++Debug.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "LibC++Debug.cc"; sourceTree = ""; }; 27DBD096246C99AF002FD7A7 /* mergeIntoStaticLib.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = mergeIntoStaticLib.sh; sourceTree = ""; }; 27DBD097246C9DE7002FD7A7 /* CBLDatabase+Apple.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "CBLDatabase+Apple.mm"; sourceTree = ""; }; + 40EBC23E298D896D00182F16 /* CBLUserAgent.hh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CBLUserAgent.hh; sourceTree = ""; }; + 40EBC252298D8A9900182F16 /* CBLUserAgent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CBLUserAgent.mm; sourceTree = ""; }; 932062DA26BC6B43006917A5 /* CBLQuery.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CBLQuery.cc; sourceTree = ""; }; 9320630126BDB340006917A5 /* CBLPlatform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CBLPlatform.h; sourceTree = ""; }; 9320631126BDB5CA006917A5 /* CBLPlatform_CAPI+Android.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "CBLPlatform_CAPI+Android.cc"; sourceTree = ""; }; 9320631426BDD059006917A5 /* CBLDatabase+Android.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "CBLDatabase+Android.cc"; sourceTree = ""; }; + 934AD381270E797D0038D62E /* CBLLog_Internal.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CBLLog_Internal.hh; sourceTree = ""; }; 93965A6226A7CD50008728EE /* LogTest.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LogTest.cc; sourceTree = ""; }; - 93C70D3326D01B5A0093E927 /* BlobTest.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = BlobTest.cc; sourceTree = ""; }; 93C70CD226C4D3F20093E927 /* CBLEncryptable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CBLEncryptable.h; sourceTree = ""; }; 93C70CE226C5B4BC0093E927 /* CBLEncryptable_CAPI.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CBLEncryptable_CAPI.cc; sourceTree = ""; }; 93C70D1626CB334D0093E927 /* ReplicatorPropEncTest.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ReplicatorPropEncTest.cc; sourceTree = ""; }; + 93C70D3326D01B5A0093E927 /* BlobTest.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = BlobTest.cc; sourceTree = ""; }; 93D0AFF1262619B800777AFC /* generate_edition_header.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = generate_edition_header.sh; sourceTree = ""; }; 93E490C326BDE10F0091B587 /* DatabaseTest_Android.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DatabaseTest_Android.cc; sourceTree = ""; }; 93EC365D26C498AB00182B02 /* CBLEncryptable_Internal.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CBLEncryptable_Internal.hh; sourceTree = ""; }; @@ -455,7 +444,6 @@ 27B61DBF21DD33930027CCDB /* Doxyfile */, 27B61DC321DEE1C20027CCDB /* CMakeLists.txt */, 273CD2D025E81C8F00B93C59 /* cmake */, - 27C9B5B921F12C970040BC45 /* python */, 27B61D8321D6B9F60027CCDB /* Xcode */, 271C2A3721CAC9B50045856E /* vendor */, 271C2A2421CAC8920045856E /* Products */, @@ -513,11 +501,14 @@ 271C2A7721CC750E0045856E /* CBLDocument.cc */, 277FEE7A21ED6C0000B60E3C /* CBLDocument_Internal.hh */, 93EC365D26C498AB00182B02 /* CBLEncryptable_Internal.hh */, + 934AD381270E797D0038D62E /* CBLLog_Internal.hh */, 277B77D4245B44E900B222D3 /* CBLLog.cc */, 932062DA26BC6B43006917A5 /* CBLQuery.cc */, 27DBCF2E246B4352002FD7A7 /* CBLQuery_Internal.hh */, 27D11BFF235140E300C58A70 /* CBLReplicator_Internal.hh */, 277FEE7621ED62AA00B60E3C /* CBLReplicatorConfig.hh */, + 40EBC23E298D896D00182F16 /* CBLUserAgent.hh */, + 40EBC252298D8A9900182F16 /* CBLUserAgent.mm */, 27D11BEE2351043B00C58A70 /* ConflictResolver.cc */, 27D11BED2351043B00C58A70 /* ConflictResolver.hh */, 271C2A7421CC4BD60045856E /* Internal.cc */, @@ -663,31 +654,6 @@ path = xcconfigs; sourceTree = ""; }; - 27C9B5B921F12C970040BC45 /* python */ = { - isa = PBXGroup; - children = ( - 2779ED5022E2493F0026ACD0 /* build_python.sh */, - 27C9B5BA21F12C970040BC45 /* test.py */, - 27C9B5BB21F12C970040BC45 /* CouchbaseLite */, - ); - name = python; - path = bindings/python; - sourceTree = ""; - }; - 27C9B5BB21F12C970040BC45 /* CouchbaseLite */ = { - isa = PBXGroup; - children = ( - 27C9B5BF21F12C970040BC45 /* BuildPyCBL.py */, - 27C9B5C321F12C970040BC45 /* common.py */, - 2779ED2722DE83A60026ACD0 /* Blob.py */, - 2779ED3622DE83A60026ACD0 /* Collections.py */, - 27C9B5C021F12C970040BC45 /* Database.py */, - 27C9B5C421F12C970040BC45 /* Document.py */, - 27C9B5DC21F29D500040BC45 /* Query.py */, - ); - path = CouchbaseLite; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -707,6 +673,7 @@ 271C2A3421CAC98F0045856E /* CBLDatabase.h in Headers */, 271C2A3121CAC98F0045856E /* CBLReplicator.h in Headers */, 271C2A3221CAC98F0045856E /* CBLBase.h in Headers */, + 40EBC24F298D89CE00182F16 /* CBLUserAgent.hh in Headers */, 27886C8D21F64C1400069BEA /* Listener.hh in Headers */, 93EC366226C49AF700182B02 /* CBLEncryptable_Internal.hh in Headers */, ); @@ -763,21 +730,6 @@ passBuildSettingsInEnvironment = 1; productName = Doxygen; }; - 2779ED5122E287FB0026ACD0 /* Python */ = { - isa = PBXLegacyTarget; - buildArgumentsString = ""; - buildConfigurationList = 2779ED5222E287FB0026ACD0 /* Build configuration list for PBXLegacyTarget "Python" */; - buildPhases = ( - ); - buildToolPath = Xcode/build_python.sh; - buildWorkingDirectory = "$(SRCROOT)"; - dependencies = ( - 2779ED5622E2881B0026ACD0 /* PBXTargetDependency */, - ); - name = Python; - passBuildSettingsInEnvironment = 1; - productName = Python; - }; /* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ @@ -900,9 +852,6 @@ 275B357B234812C700FE9CF0 = { CreatedOnToolsVersion = 11.1; }; - 2779ED5122E287FB0026ACD0 = { - CreatedOnToolsVersion = 11.0; - }; 27984E092249A126000FE777 = { CreatedOnToolsVersion = 10.2; }; @@ -938,7 +887,6 @@ 27B61DA721D6E49D0027CCDB /* CBL_Tests */, 275B357B234812C700FE9CF0 /* CouchbaseLiteTests */, 272F012A2279037600E62F72 /* Doxygen */, - 2779ED5122E287FB0026ACD0 /* Python */, ); }; /* End PBXProject section */ @@ -1230,6 +1178,7 @@ 277B77D5245B44E900B222D3 /* CBLLog.cc in Sources */, 271C2A7221CADB170045856E /* CBLDatabase.cc in Sources */, 276633A62602815000B9BD36 /* CBLDatabase_CAPI.cc in Sources */, + 40EBC260298D8A9900182F16 /* CBLUserAgent.mm in Sources */, 27DBD098246C9DE7002FD7A7 /* CBLDatabase+Apple.mm in Sources */, 275BC4DE2201323700DBE7D2 /* CBLBlob_CAPI.cc in Sources */, 271C2A7821CC750E0045856E /* CBLDocument.cc in Sources */, @@ -1322,11 +1271,6 @@ target = 27B61D6F21D6B64A0027CCDB /* CBL_C Dylib */; targetProxy = 275B358F234BCF6900FE9CF0 /* PBXContainerItemProxy */; }; - 2779ED5622E2881B0026ACD0 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 27B61D6F21D6B64A0027CCDB /* CBL_C Dylib */; - targetProxy = 2779ED5522E2881B0026ACD0 /* PBXContainerItemProxy */; - }; 277CC9AD22BC3E2800B245CB /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = LiteCoreWebSocket; @@ -1519,129 +1463,10 @@ }; name = Release; }; - 2779ED5322E287FB0026ACD0 /* 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++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_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; - CODE_SIGN_STYLE = Automatic; - COPY_PHASE_STRIP = NO; - DEBUGGING_SYMBOLS = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = N2Q372V7W2; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_GENERATE_DEBUGGING_SYMBOLS = YES; - 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; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 2779ED5422E287FB0026ACD0 /* 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++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_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; - CODE_SIGN_STYLE = Automatic; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = N2Q372V7W2; - 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; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; 27984E1C2249A127000FE777 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 27310FD7235F686D0046F8C8 /* CBL_Framework_Debug.xcconfig */; buildSettings = { - CODE_SIGN_IDENTITY = "-"; - DEVELOPMENT_TEAM = N2Q372V7W2; ENABLE_HARDENED_RUNTIME = YES; }; name = Debug; @@ -1650,8 +1475,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 27984E492249AF61000FE777 /* CBL_Framework_Release.xcconfig */; buildSettings = { - CODE_SIGN_IDENTITY = "Apple Development"; - DEVELOPMENT_TEAM = N2Q372V7W2; ENABLE_HARDENED_RUNTIME = YES; }; name = Release; @@ -1811,8 +1634,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 27310FD7235F686D0046F8C8 /* CBL_Framework_Debug.xcconfig */; buildSettings = { - CODE_SIGN_IDENTITY = "-"; - DEVELOPMENT_TEAM = N2Q372V7W2; ENABLE_HARDENED_RUNTIME = YES; }; name = Debug_EE; @@ -1945,69 +1766,6 @@ }; name = Debug_EE; }; - 27D055722358F9DF009BB0A1 /* Debug_EE */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - 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_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; - CODE_SIGN_STYLE = Automatic; - COPY_PHASE_STRIP = NO; - DEBUGGING_SYMBOLS = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = N2Q372V7W2; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_GENERATE_DEBUGGING_SYMBOLS = YES; - 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; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug_EE; - }; 27D055812358F9FA009BB0A1 /* Release_EE */ = { isa = XCBuildConfiguration; baseConfigurationReference = 27D0558A2358FA67009BB0A1 /* Project_Release_EE.xcconfig */; @@ -2035,8 +1793,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 27984E492249AF61000FE777 /* CBL_Framework_Release.xcconfig */; buildSettings = { - CODE_SIGN_IDENTITY = "Apple Development"; - DEVELOPMENT_TEAM = N2Q372V7W2; ENABLE_HARDENED_RUNTIME = YES; }; name = Release_EE; @@ -2154,60 +1910,6 @@ }; name = Release_EE; }; - 27D055882358F9FA009BB0A1 /* Release_EE */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - 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_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; - CODE_SIGN_STYLE = Automatic; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = N2Q372V7W2; - 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; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release_EE; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -2255,17 +1957,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 2779ED5222E287FB0026ACD0 /* Build configuration list for PBXLegacyTarget "Python" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2779ED5322E287FB0026ACD0 /* Debug */, - 27D055722358F9DF009BB0A1 /* Debug_EE */, - 2779ED5422E287FB0026ACD0 /* Release */, - 27D055882358F9FA009BB0A1 /* Release_EE */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 27984E1B2249A127000FE777 /* Build configuration list for PBXNativeTarget "CBL_C Framework" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/CBL_C.xcodeproj/xcshareddata/xcschemes/Doxygen.xcscheme b/CBL_C.xcodeproj/xcshareddata/xcschemes/Doxygen.xcscheme new file mode 100644 index 00000000..a68abb5f --- /dev/null +++ b/CBL_C.xcodeproj/xcshareddata/xcschemes/Doxygen.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CMakeLists.txt b/CMakeLists.txt index f21beb5a..3e172e98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,11 +7,19 @@ if(NOT DEFINED CMAKE_OSX_SYSROOT) endif() set(CMAKE_OSX_ARCHITECTURES x86_64 arm64) -set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15) +set(CMAKE_OSX_DEPLOYMENT_TARGET 10.14) + +if(DEFINED ENV{VERSION}) + message(VERBOSE "Using VERSION:$ENV{VERSION} from environment variable") + set(CBL_VERSION_STRING $ENV{VERSION}) +else() + message(WARNING "No VERSION set, defaulting to 0.0.0") + set(CBL_VERSION_STRING "0.0.0") +endif() project ( CouchbaseLite_C - VERSION 3.0.0 + VERSION ${CBL_VERSION_STRING} ) set(CBL_LIB_VERSION ${CouchbaseLite_C_VERSION}) diff --git a/Doxyfile b/Doxyfile index 5f6ddd1d..f8001933 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.8.12 +# Doxyfile 1.9.2 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -17,11 +17,11 @@ # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 @@ -58,7 +58,7 @@ PROJECT_LOGO = # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = "docs/C/" +OUTPUT_DIRECTORY = docs/C/ # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and @@ -171,7 +171,7 @@ STRIP_FROM_PATH = # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = "include" +STRIP_FROM_INC_PATH = include # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -189,6 +189,16 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus @@ -209,6 +219,14 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. @@ -232,20 +250,19 @@ TAB_SIZE = 4 # the documentation. An alias has the form: # name=value # For example adding -# "sideeffect=@par Side Effects:\n" +# "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) ALIASES = -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -274,28 +291,40 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: -# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: -# Fortran. In the later case the parser tries to guess whether the code is fixed -# or free formatted code, this is the default for Fortran type files), VHDL. For -# instance to make doxygen treat .inc files as Fortran files (default is PHP), -# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. +# documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. @@ -307,7 +336,7 @@ MARKDOWN_SUPPORT = YES # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 0. +# Minimum value: 0, maximum value: 99, default value: 5. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 0 @@ -337,7 +366,7 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. @@ -423,6 +452,19 @@ TYPEDEF_HIDES_STRUCT = YES LOOKUP_CACHE_SIZE = 0 +# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -443,6 +485,12 @@ EXTRACT_ALL = YES EXTRACT_PRIVATE = NO +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. @@ -480,6 +528,13 @@ EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation @@ -497,8 +552,8 @@ HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO, these declarations will be -# included in the documentation. +# declarations. If set to NO, these declarations will be included in the +# documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO @@ -517,11 +572,18 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES, upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. # The default value is: system dependent. CASE_SENSE_NAMES = NO @@ -540,6 +602,12 @@ HIDE_SCOPE_NAMES = NO HIDE_COMPOUND_REFERENCE= NO +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -697,7 +765,8 @@ FILE_VERSION_FILTER = # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE @@ -708,7 +777,7 @@ LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. @@ -743,23 +812,35 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. WARN_AS_ERROR = YES @@ -790,13 +871,14 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = "include/cbl" "vendor/couchbase-lite-core/vendor/fleece/API/fleece" +INPUT = include/cbl \ + vendor/couchbase-lite-core/vendor/fleece/API/fleece # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of -# possible encodings. +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 @@ -809,11 +891,15 @@ INPUT_ENCODING = UTF-8 # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, -# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.h @@ -968,7 +1054,7 @@ INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. +# entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO @@ -1000,12 +1086,12 @@ SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version +# (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # @@ -1038,13 +1124,6 @@ VERBATIM_HEADERS = YES ALPHABETICAL_INDEX = YES -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored @@ -1144,8 +1223,8 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. @@ -1154,7 +1233,7 @@ HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A +# in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1181,6 +1260,17 @@ HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = NO +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. @@ -1204,13 +1294,14 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1249,8 +1340,12 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1280,7 +1375,7 @@ CHM_FILE = HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the master .chm file (NO). +# (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1325,7 +1420,8 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1333,8 +1429,8 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1342,30 +1438,30 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = @@ -1408,16 +1504,28 @@ DISABLE_INDEX = NO # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATOR_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # @@ -1442,6 +1550,17 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML @@ -1451,7 +1570,7 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # @@ -1462,8 +1581,14 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1473,11 +1598,29 @@ FORMULA_TRANSPARENT = YES USE_MATHJAX = NO +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + # When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1490,22 +1633,29 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html +# #tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1533,7 +1683,7 @@ MATHJAX_CODEFILE = SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using Javascript. There +# implemented using a web server instead of a web client using JavaScript. There # are two flavors of web server based searching depending on the EXTERNAL_SEARCH # setting. When disabled, doxygen will generate a PHP script for searching and # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing @@ -1552,7 +1702,8 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: +# https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1565,8 +1716,9 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and -# Searching" for details. +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = @@ -1617,21 +1769,35 @@ LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. # -# Note that when enabling USE_PDFLATEX this option is only used for generating -# bitmaps for formulas in the HTML output, but not in the Makefile that is -# written to the output directory. -# The default file is: latex. +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. MAKEINDEX_CMD_NAME = makeindex +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = makeindex + # If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. @@ -1661,29 +1827,31 @@ PAPER_TYPE = a4 EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the -# generated LaTeX document. The header should contain everything until the first -# chapter. If it is left blank doxygen will generate a standard header. See -# section "Doxygen usage" for information on how to let doxygen write the -# default header to a separate file. +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. # -# Note: Only use a user-defined header if you know what you are doing! The -# following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empty -# string, for the replacement values of the other commands the user is referred -# to HTML_HEADER. +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the -# generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. See +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what -# special commands can be used inside the footer. -# -# Note: Only use a user-defined footer if you know what you are doing! +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = @@ -1716,9 +1884,11 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES, to get a -# higher quality PDF documentation. +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1726,8 +1896,7 @@ USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode # command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. This option is also used -# when generating formulas in HTML. +# if errors occur, instead of asking the user for help. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1740,19 +1909,9 @@ LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO -# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source -# code with syntax highlighting in the LaTeX output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_SOURCE_CODE = NO - # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1766,6 +1925,14 @@ LATEX_BIB_STYLE = plain LATEX_TIMESTAMP = NO +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- @@ -1805,9 +1972,9 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's config -# file, i.e. a series of assignments. You only have to provide replacements, -# missing definitions are set to their default value. +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. # # See also section "Doxygen usage" for information on how to generate the # default style sheet that doxygen normally uses. @@ -1816,22 +1983,12 @@ RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is -# similar to doxygen's config file. A template extensions file can be generated -# using doxygen -e rtf extensionFile. +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_EXTENSIONS_FILE = -# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code -# with syntax highlighting in the RTF output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_RTF is set to YES. - -RTF_SOURCE_CODE = NO - #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- @@ -1903,6 +2060,13 @@ XML_OUTPUT = xml XML_PROGRAMLISTING = YES +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- @@ -1921,23 +2085,14 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook -# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the -# program listings (including syntax highlighting and cross-referencing -# information) to the DOCBOOK output. Note that enabling this will significantly -# increase the size of the DOCBOOK output. -# The default value is: NO. -# This tag requires that the tag GENERATE_DOCBOOK is set to YES. - -DOCBOOK_PROGRAMLISTING = NO - #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sf.net) file that captures the -# structure of the code including all documentation. Note that this feature is -# still experimental and incomplete at the moment. +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO @@ -2037,7 +2192,13 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = DOXYGEN_PARSING=1 CBLAPI= _cbl_nonnull= FLAPI= FLNONNULL= NONNULL= COUCHBASE_ENTERPRISE= +PREDEFINED = DOXYGEN_PARSING=1 \ + CBLAPI= \ + _cbl_nonnull= \ + FLAPI= \ + FLNONNULL= \ + NONNULL= \ + COUCHBASE_ENTERPRISE= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -2046,7 +2207,9 @@ PREDEFINED = DOXYGEN_PARSING=1 CBLAPI= _cbl_nonnull= FLAPI= FLNONNUL # definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_AS_DEFINED = CBL_OPTIONS CBL_ENUM CBL_REFCOUNTED +EXPAND_AS_DEFINED = CBL_OPTIONS \ + CBL_ENUM \ + CBL_REFCOUNTED # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will # remove all references to function-like macros that are alone on a line, have @@ -2104,12 +2267,6 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- @@ -2123,15 +2280,6 @@ PERL_PATH = /usr/bin/perl CLASS_DIAGRAMS = YES -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. @@ -2229,10 +2377,32 @@ UML_LOOK = NO # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. +# This tag requires that the tag UML_LOOK is set to YES. UML_LIMIT_NUM_FIELDS = 10 +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will wrapped across multiple lines. Some heuristics are apply +# to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their # instances. @@ -2359,6 +2529,11 @@ DIAFILE_DIRS = PLANTUML_JAR_PATH = +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + # When using plantuml, the specified paths are searched for files specified by # the !include statement in a plantuml block. @@ -2417,9 +2592,11 @@ DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc temporary +# files. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES diff --git a/Jenkinsfile b/Jenkinsfile index 794fa4dd..ecb41d88 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -28,8 +28,6 @@ pipeline { agent { label 's61113u16 (litecore)' } environment { BRANCH = "${BRANCH_NAME}" - CC = "gcc-7" - CXX = "g++-7" } steps { sh 'jenkins/jenkins_unix.sh' diff --git a/README.md b/README.md index 4f4aac30..f29aa674 100644 --- a/README.md +++ b/README.md @@ -2,25 +2,14 @@ This is a cross-platform version of the [Couchbase Lite][CBL] embedded NoSQL syncable database, with a plain C API. The API can be used directly, or as the substrate for binding to other languages like Python, JavaScript or Rust. -## What's New (May 2020) - -**This project is close to beta status.** The API is nearly complete and almost all of the functionality is implemented, but there are still missing pieces and only limited testing. - -* New Rust and Nim language bindings! They're in the new top-level `bindings` directory. The Python binding has been moved there too. -* Added variants of many API functions, which take slices (`FLSlice`) instead of C strings. These are more efficient to call from languages whose native string type is not NUL-terminated, such as Rust. -* Added `CBLResultSet_RowArray()`, `CBLResultSet_RowDict()`, and `CBLResultSet_GetQuery()`. -* More of the logging API (in `CBLLog.h`) is implemented, including custom log callbacks. -* Updated to latest Couchbase Lite Core (LiteCore). - ## Goals - [x] C API - [x] Similar to to other Couchbase Lite platforms (Java, C#, Swift, Objective-C) - [x] Clean and regular design - [x] Comes with a C++ wrapper API, implemented as inline calls to C - - [x] Experimental Python binding (made using `cffi`) - - [x] Can be bound to [other languages](#other-language-bindings) like Go or JavaScript -- [ ] Same feature set as other Couchbase Lite platforms + - [x] Can be bound to [other languages](#other-language-bindings) like Python, Go, or JavaScript +- [x] Same feature set as other Couchbase Lite platforms - [x] Schemaless JSON data model - [x] Standard CRUD operations - [x] Efficient binary blob support @@ -36,19 +25,18 @@ This is a cross-platform version of the [Couchbase Lite][CBL] embedded NoSQL syn - [x] Replicator online/offline support and retry behavior - [x] Replicator TLS/SSL support - [ ] Peer-to-peer replication -- [x] Minimal platform dependencies: C++ standard library, filesystem, TCP/IP -- [ ] Broad OS support - - [x] macOS, for ease of development - - [x] Common Linux distros, esp. Ubuntu, Fedora, Raspbian (q.v.) - - [x] Windows - - [x] iOS - - [ ] Android (but we have a [Couchbase Lite For Android][ANDROID] already, with a Java API) +- [x] Minimal platform dependencies: C++ standard library, filesystem, TCP/IP, libz (macOS / Linux), libicu (Linux) +- [x] Broad official OS support + - [x] macOS (x86_64 and arm64) + - [x] Debian 9/10 (including Raspbian / Raspberry Pi OS) and Ubuntu 20.04 (x86_64, armhf, arm64) + - [x] Windows (x86_64 only) + - [x] iOS (device and simulator archs) + - [x] Android (armeabi-v7a, arm64-v8a, x86, x86_64) - [x] Runs on Raspberry-Pi-level embedded platforms with… - 32-bit or 64-bit CPU - ARM or x86 - Hundreds of MB RAM, hundreds of MHz CPU, tens of MB storage - Linux-based OS - - Stretch goal: Simpler embedded kernels like mbedOS or ESP-IDF. ## Examples @@ -57,33 +45,32 @@ This is a cross-platform version of the [Couchbase Lite][CBL] embedded NoSQL syn ```c // Open a database: CBLError error; -CBLDatabaseConfiguration config = {"/tmp", kCBLDatabase_Create}; -CBLDatabase* db = CBLDatabase_Open("my_db", &config, &error); +CBLDatabaseConfiguration config = {FLSTR("/tmp")}; +CBLDatabase* db = CBLDatabase_Open(FLSTR("my_db"), &config, &error); // Create a document: -CBLDocument* doc = CBLDocument_New("foo"); +CBLDocument* doc = CBLDocument_CreateWithID(FLSTR("foo")); FLMutableDict props = CBLDocument_MutableProperties(doc); -FLSlot_SetString(FLMutableDict_Set(dict, FLStr("greeting")), FLStr("Howdy!")); +FLSlot_SetString(FLMutableDict_Set(props, FLStr("greeting")), FLStr("Howdy!")); // Save the document: -const CBLDocument *saved = CBLDatabase_SaveDocument(db, doc, - kCBLConcurrencyControlFailOnConflict, - &error); -CBLDocument_Release(saved); +CBLDatabase_SaveDocument(db, doc, &error); CBLDocument_Release(doc); // Read it back: -const CBLDocument *readDoc = CBLDatabase_GetDocument(db, "foo"); +const CBLDocument *readDoc = CBLDatabase_GetDocument(db, FLSTR("foo"), &error); FLDict readProps = CBLDocument_Properties(readDoc); FLSlice greeting = FLValue_AsString( FLDict_Get(readProps, FLStr("greeting")) ); CBLDocument_Release(readDoc); ``` -### C++ +### Others + +**NOTE**: The C++ API is not part of the official release. ```cpp // Open a database: -cbl::Database db(kDatabaseName, {"/tmp", kCBLDatabase_Create}); +cbl::Database db(kDatabaseName, {"/tmp"}); // Create a document: cbl::MutableDocument doc("foo"); @@ -91,97 +78,72 @@ doc["greeting"] = "Howdy!"; db.saveDocument(doc); // Read it back: -cbl::Document doc = db.getMutableDocument("foo"); -fleece::Dict readProps = doc->properties(); +cbl::Document readDoc = db.getMutableDocument("foo"); +fleece::Dict readProps = readDoc.properties(); fleece::slice greeting = readProps["greeting"].asString(); ``` -### Nim - -```nim -# Open a database: -let config = DatabaseConfiguration(directory: "/tmp", flags: {DatabaseFlag.create}) -var db = openDatabase("nim_db", config) - -# Create a document: -var doc = newDocument("foo") -doc["greeting"] = "Howdy!" -db.saveDocument(doc) - -# Read it back: -let readDoc = db.getDocument("foo") -let readProps = readDoc.properties -let greeting = readProps["greeting"] -``` - -### Python - -```python -# Open a database: -db = Database("python_db", DatabaseConfiguration("/tmp")); - -# Create a document: -doc = MutableDocument("foo") -doc["greeting"] = "Howdy!" -db.saveDocument(doc) - -# Read it back: -readDoc = db.getDocument("foo") -readProps = readDoc.properties -greeting = readProps["greeting"] -``` - -### Rust - -```rust -// Open a database: -let cfg = DatabaseConfiguration{directory: tmp_dir.path(), flags: CREATE}; -let mut db = Database::open("rust_db, Some(cfg)).expect("opening db"); - -// Create a document: -let mut doc = Document::new_with_id("foo"); -let mut props = doc.mutable_properties(); -props.at("greeting").put_string("Howdy!"); -db.save_document(&mut doc, ConcurrencyControl::FailOnConflict).expect("saving"); - -// Read it back: -let doc = db.get_document("foo").expect("reload document"); -let props = doc.properties(); -let greeting = props.get("greeting"); -``` - ## Documentation -* [Couchbase Lite documentation](https://docs.couchbase.com/couchbase-lite/2.7/introduction.html) is a must-read to learn the architecture and the API concepts, even though the API details are different here. -* [C API documentation](http://labs.couchbase.com/couchbase-lite-C/C/html/modules.html) (generated by Doxygen) -* Or you could just [read the header files](https://github.com/couchbaselabs/couchbase-lite-C/tree/master/include/cbl) +* [Couchbase Lite documentation](https://docs.couchbase.com/couchbase-lite/current/introduction.html) is a must-read to learn the architecture and the API concepts, even though the API details are different here. +* API documentation in [the header files](https://github.com/couchbaselabs/couchbase-lite-C/tree/master/include/cbl) * [Using Fleece](https://github.com/couchbaselabs/fleece/wiki/Using-Fleece) — Fleece is the API for document properties * [Contributor guidelines](CONTRIBUTING.md), should you wish to submit bug fixes, tests, or other improvements ## Building It -### With CMake on Unix (now including Raspberry Pi!) +### CMake on Unix (normal compile) Dependencies: * GCC 7+ or Clang -* CMake 3.9+ -* ICU libraries (`apt-get install icu-dev`) +* CMake 3.10+ +* (Linux) ICU development libraries (`apt-get install icu-dev`) +* (Linux) ZLIB development libraries (`apt-get install zlib1g-dev`) 1. Clone the repo 2. Check out submodules (recursively), i.e. `git submodule update --init --recursive` -3. Run the shellscript `build.sh` -6. Run the unit tests, with `test.sh` +3. Prepare the build project with CMake (e.g. `cmake `) +4. Build the project: `make cblite` + +The resulting (debug by default) libraries are +- Linux: `libcblite.so*` (e.g. libcblite.so.3.0.0 / libcblite.so.3 / libcblite.so) +- macOS: `libcblite.*.dylib` (e.g. libcblite.3.0.0.dylib / libcblite.3.dylib / libcblite.dylib) -The library is at `build_cmake/libcblite.so`. (Or `.DLL` or `.dylib`) +### CMake on Linux (cross compile) + +**NOTE**: Due to the complexity of cross compiling, these instructions are very high level on purpose. If you are curious about more fine-grained details you can check out the [cross compilation script](https://raw.githubusercontent.com/couchbase/couchbase-lite-C/master/jenkins/ci_cross_build.py) we use. + +Dependencies: +* Cross compiler based on GCC 7+ or clang +* CMake 3.10+ +* (in sysroot) ICU development libraries +* (in sysroot) ZLIB development libraries + +1. Clone the repo +2. Check out submodules (recursively), i.e. `git submodule update --init --recursive` +3. Create a CMake toolchain file that sets up the cross compiler and sysroot for the cross compilation +4. Prepare the build project with CMake and the toolchain from 3 (e.g. `cmake -DCMAKE_TOOLCHAIN_FILE= `) +5. Build the project `make cblite` ### With CMake on Windows -_(Much like building on Unix. Details TBD)_ +Dependencies: +* Visual Studio Toolset v141+ (Visual Studio 2017+) +* CMake 3.10+ + +1. Clone the repo +2. Check out submodules (recursively), i.e. `git submodule update --init --recursive` +3. Prepare the build project with CMake (e.g. `cmake -G -A x64`). Note even if you don't want to install, you should set the `CMAKE_INSTALL_PREFIX` (see issue #141). +4. Build the project: `cmake --build . --target cblite` (or open the resulting Visual Studio project and build from there) + +The resulting (debug by default) library is `Debug\cblite.dll`. ### With Xcode on macOS +:warning: Do not use Xcode 13 because of a [downstream issue](https://github.com/ARMmbed/mbedtls/issues/5052) :warning: + 1. Clone the repo -2. Check out submodules (recursively) +2. Check out submodules (recursively), i.e. `git submodule update --init --recursive` 3. Open the Xcode project in the `Xcode` subfolder 4. Select scheme `CBL_C Framework` 5. Build @@ -193,6 +155,26 @@ To run the unit tests: 4. Select scheme `CBL_Tests` 5. Run +## Testing It + +### CMake on Unix + +1. Follow the steps in building +2. Build the test project `make CBL_C_Tests` +3. Run the tests in `test` directory `./CBL_C_Tests -r list` (for cross compile, this step needs to be done on the target system) + +### CMake on Windows + +1. Follow the steps in building +2. Build the test project `cmake --build . --target CBL_C_Tests` +3. Run the tests in `test\Debug` directory `.\CBL_C_Tests.exe -r list` + +### With Xcode on macOS + +1. Open the Xcode project from the Building section +2. Select scheme `CBL_Tests` +3. Run + ## Using It ### Generic instructions @@ -216,8 +198,12 @@ To run the unit tests: ## Other Language Bindings -* **C++**: Already included; see [`include/cbl++`](https://github.com/couchbaselabs/couchbase-lite-C/tree/master/include/cbl%2B%2B) -* **Python**: [Included](bindings/python/README.md) but unsupported -* **Nim**: [Included](bindings/nim/README.md) but unsupported -* **Rust**: [Included](bindings/rust/README.md) but unsupported -* **Go** (Golang): [Third-party, in progress](https://github.com/svr4/couchbase-lite-cgo). +All of these (even C++) have no official support by Couchbase. + +If you've created a language binding, please let us know by filing an issue, or a PR that updates the list below. + +* **C++**: Already included; see [`include/cbl++`](https://github.com/couchbase/couchbase-lite-C/tree/master/include/cbl%2B%2B) +* **Go** (Golang): [Third-party, in progress](https://github.com/svr4/couchbase-lite-cgo) +* **Nim**: [couchbase-lite-nim](https://github.com/couchbaselabs/couchbase-lite-nim) +* **Python**: [couchbase-lite-python](https://github.com/couchbaselabs/couchbase-lite-python) +* **Rust**: [couchbase-lite-rust](https://github.com/couchbaselabs/couchbase-lite-rust) diff --git a/Xcode/CouchbaseLite.modulemap b/Xcode/CouchbaseLite.modulemap index ba12e3c2..7e8d71f3 100644 --- a/Xcode/CouchbaseLite.modulemap +++ b/Xcode/CouchbaseLite.modulemap @@ -6,6 +6,8 @@ framework module CouchbaseLite { header "CBLBlob.h" header "CBLDatabase.h" header "CBLDocument.h" + header "CBLEncryptable.h" + header "CBLPlatform.h" header "CBLLog.h" header "CBLQuery.h" header "CBLReplicator.h" diff --git a/Xcode/build_python.sh b/Xcode/build_python.sh deleted file mode 100755 index c988a655..00000000 --- a/Xcode/build_python.sh +++ /dev/null @@ -1,19 +0,0 @@ -#! /bin/bash -e - -PY_SRC="$SRCROOT/python/CouchbaseLite" -PY_DST="$TARGET_BUILD_DIR/python/CouchbaseLite" - -# TEMP!! Fixes compatibility issue with distutils -export MACOSX_DEPLOYMENT_TARGET=10.14 - -# Create and populate the Python build directory -rm -rf "$PY_DST" -mkdir -p "$PY_DST" -cd "$PY_DST" -cp "$PY_SRC"/*.py . - -/usr/local/bin/python3 "$SRCROOT/python/BuildPyCBL.py" \ - --srcdir "$SRCROOT" \ - --libdir "$TARGET_BUILD_DIR" - -echo "Python package created at $PY_DST" diff --git a/Xcode/xcconfigs/CBL_Dylib_Release.xcconfig b/Xcode/xcconfigs/CBL_Dylib_Release.xcconfig index fb8d7a6c..c7d7ea05 100644 --- a/Xcode/xcconfigs/CBL_Dylib_Release.xcconfig +++ b/Xcode/xcconfigs/CBL_Dylib_Release.xcconfig @@ -8,3 +8,7 @@ #include "CBL_dylib.xcconfig" #include "vendor/couchbase-lite-core/Xcode/xcconfigs/dylib_Release.xcconfig" + +CODE_SIGNING_ALLOWED = YES +CODE_SIGN_IDENTITY = Apple Development +DEVELOPMENT_TEAM = N2Q372V7W2 diff --git a/Xcode/xcconfigs/CBL_Framework.xcconfig b/Xcode/xcconfigs/CBL_Framework.xcconfig index bdd9fc9e..bb895a3e 100644 --- a/Xcode/xcconfigs/CBL_Framework.xcconfig +++ b/Xcode/xcconfigs/CBL_Framework.xcconfig @@ -10,7 +10,9 @@ INSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Frameworks LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @loader_path/Frameworks +CODE_SIGN_IDENTITY = Apple Development DEFINES_MODULE = YES +DEVELOPMENT_TEAM = N2Q372V7W2 EXECUTABLE_PREFIX = FRAMEWORK_VERSION = A INFOPLIST_FILE = Xcode/Framework-Info.plist diff --git a/Xcode/xcconfigs/CBL_dylib.xcconfig b/Xcode/xcconfigs/CBL_dylib.xcconfig index 415dc52b..ea9f0cf4 100644 --- a/Xcode/xcconfigs/CBL_dylib.xcconfig +++ b/Xcode/xcconfigs/CBL_dylib.xcconfig @@ -10,3 +10,4 @@ PRODUCT_NAME = cblite EXPORTED_SYMBOLS_FILE = $(DERIVED_FILE_DIR)/CBL.exp // output of src/exports/generate_exports.sh +CODE_SIGNING_ALLOWED = NO diff --git a/Xcode/xcconfigs/Project.xcconfig b/Xcode/xcconfigs/Project.xcconfig index fc909bfd..6817a37a 100644 --- a/Xcode/xcconfigs/Project.xcconfig +++ b/Xcode/xcconfigs/Project.xcconfig @@ -11,11 +11,11 @@ LITECORE = vendor/couchbase-lite-core FLEECE = $(LITECORE)/vendor/fleece -CBL_VERSION_STRING = 3.0.0 +CBL_VERSION_STRING = 3.0.3 CBL_BUILD_NUMBER = 0 -IPHONEOS_DEPLOYMENT_TARGET = 11.0 -MACOSX_DEPLOYMENT_TARGET = 10.13 -TVOS_DEPLOYMENT_TARGET = 11.0 +IPHONEOS_DEPLOYMENT_TARGET = 10.0 +MACOSX_DEPLOYMENT_TARGET = 10.14 +TVOS_DEPLOYMENT_TARGET = 10.0 SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator VALID_ARCHS = arm64 x86_64 diff --git a/Xcode/xcconfigs/Tests.xcconfig b/Xcode/xcconfigs/Tests.xcconfig index 679281c1..7f7ff637 100644 --- a/Xcode/xcconfigs/Tests.xcconfig +++ b/Xcode/xcconfigs/Tests.xcconfig @@ -8,5 +8,9 @@ HEADER_SEARCH_PATHS = include Xcode/generated_headers/public/cbl $(FLEECE)/API $(FLEECE)/Fleece/Support $(FLEECE)/vendor/catch PRODUCT_NAME = cbl_tests +CODE_SIGNING_ALLOWED = NO +LLVM_LTO = NO // LTO makes tests very slow to link and confuses Instruments -LLVM_LTO = NO // LTO makes tests very slow to link and confuses Instruments +CLANG_WARN__EXIT_TIME_DESTRUCTORS = NO +GCC_WARN_UNKNOWN_PRAGMAS = NO +CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = NO diff --git a/bindings/nim/CouchbaseLite.nimble b/bindings/nim/CouchbaseLite.nimble deleted file mode 100644 index 840f96c7..00000000 --- a/bindings/nim/CouchbaseLite.nimble +++ /dev/null @@ -1,11 +0,0 @@ -# Package - -version = "0.1.0" -author = "Couchbase, Inc." -description = "Couchbase Lite embedded NoSQL database (Nim bindings)" -license = "Apache-2.0" -srcDir = "src" - -# Dependencies - -requires "nim >= 1.2.0" diff --git a/bindings/nim/README.md b/bindings/nim/README.md deleted file mode 100644 index a7210d1e..00000000 --- a/bindings/nim/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Nim Language Bindings For Couchbase Lite - -10 May 2020 - -This directory is a package containing a [Couchbase Lite][CBL] API binding for the [Nim -language][NIM]. - -It's still in early development. It's incomplete, has only had some informal testing, and that -only on macOS. Also I (Jens) am a newbie at Nim and may not be doing things the write way. -Feedback gratefully accepted. - -## Building - -**_"Some assembly required..."_** - -You first need to build Couchbase Lite For C (the root of this repo) with CMake, by running the -`build.sh` script in the repo root directory. That will produce the shared library. - - $ cd ../.. - $ ./build.sh - -Symlink or copy the library into this directory. - - $ cd bindings/nim - $ ln -s ../../build_cmake/libcblite.dylib . - -After that, you can use [Nimble][NIMBLE] to build and run: - - $ nimble test - -When compiling on Linux system remember to set `LD_LIBRARY_PATH` to point to the -directory where `libcblite.so` exists. If you followed the above steps -this would look like this: - - $ LD_LIBRARY_PATH=. nimble test - -Without the symlink you can also do: - - $ LD_LIBRARY_PATH=../../build_cmake nimble test - -The supplied `CouchbaseLite.nimble` file is used to allow Nimble to run the -tests. If you want to try the bindings out you can create a `.nim` -file in this directory and add `bin = @[""]` to the -`CouchbaseLite.nimble` file. You can now run `nimble build` or `nimble run` to -build or build and run your file with the bindings. - -## Learning - -I've copied the doc-comments from the C API into the Nim files. But Couchbase Lite is fairly -complex, so if you're not already familiar with it, you'll want to start by reading through -the [official documentation][CBLDOCS]. - -The Nim API is mostly method-for-method compatible with the languages documented there, except -down at the document property level (dictionaries, arrays, etc.) where I haven't yet written -compatible bindings. For those APIs you can check out the document "[Using Fleece][FLEECE]". - -## Using - -[NIM]: https://nim-lang.org/ -[CBL]: https://www.couchbase.com/products/lite -[NIMBLE]: https://github.com/nim-lang/nimble#readme -[CBLDOCS]: https://docs.couchbase.com/couchbase-lite/current/introduction.html -[FLEECE]: https://github.com/couchbaselabs/fleece/wiki/Using-Fleece diff --git a/bindings/nim/monitor.sh b/bindings/nim/monitor.sh deleted file mode 100755 index 5d3c44d3..00000000 --- a/bindings/nim/monitor.sh +++ /dev/null @@ -1,7 +0,0 @@ -#! /bin/bash -e -# -# This uses the `entr` tool to re-run `nimble test` whenever any source file is saved. -# Very handy to leave running in a terminal window while you work. -# You can get `entr` from or your friendly local package manager. - -find . -name '*.nim' | entr -c -s "nimble test" diff --git a/bindings/nim/nim.cfg b/bindings/nim/nim.cfg deleted file mode 100644 index 7a96dd74..00000000 --- a/bindings/nim/nim.cfg +++ /dev/null @@ -1,6 +0,0 @@ ---path:src ---path:binding ---outdir:bin ---hints:off -#-d:nimDebugDlOpen -#--debugger:native diff --git a/bindings/nim/src/CouchbaseLite.nim b/bindings/nim/src/CouchbaseLite.nim deleted file mode 100644 index 059d5819..00000000 --- a/bindings/nim/src/CouchbaseLite.nim +++ /dev/null @@ -1,33 +0,0 @@ -# Couchbase Lite bindings for Nim; main module -# -# Copyright (c) 2020 Couchbase, Inc All rights reserved. -# -# 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 CouchbaseLite/database -import CouchbaseLite/document -import CouchbaseLite/errors -import CouchbaseLite/fleece -import CouchbaseLite/listener -import CouchbaseLite/query -import CouchbaseLite/replicator - -export database -export document -export errors -export fleece -export listener -export query -export replicator diff --git a/bindings/nim/src/CouchbaseLite/database.nim b/bindings/nim/src/CouchbaseLite/database.nim deleted file mode 100644 index bd277d94..00000000 --- a/bindings/nim/src/CouchbaseLite/database.nim +++ /dev/null @@ -1,146 +0,0 @@ -# Couchbase Lite Database class -# -# Copyright (c) 2020 Couchbase, Inc All rights reserved. -# -# 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 CouchbaseLite/errors -import CouchbaseLite/private/cbl - -import sugar - -{.experimental: "notnil".} - - -type - DatabaseObj* {.requiresInit.} = object - handle: CBLDatabase not nil - Database* = ref DatabaseObj not nil ## A connection to an open database. - - -proc `=destroy`(d: var DatabaseObj) = - release(d.handle) - -proc `=`(dst: var DatabaseObj, src: DatabaseObj) {.error.} - - -type - DatabaseFlag* {.size: sizeof(cint).} = enum - create, ## Create the database if it doesn't exist - readOnly, ## Open database read-only - noUpgrade ## Disable upgrading an older-version database - DatabaseFlags* = set[DatabaseFlag] ## Flags for how to open a database. - - EncryptionAlgorithm* = enum - ## Database encryption algorithms (available only in the Enterprise - ## Edition). - none = 0, - AES256 - EncryptionKey* = object - ## Encryption key specified in a DatabaseConfiguration. - algorithm*: EncryptionAlgorithm ## Encryption algorithm - bytes*: array[32, uint8] ## Raw key data - - DatabaseConfiguration* = object - ## Database configuration options. - directory*: string ## The parent directory of the database - flags*: DatabaseFlags ## Options for opening the database - encryptionKey*: ref EncryptionKey ## The database's encryption key (if any) - - -proc openDB(name: string; configP: ptr CBLDatabaseConfiguration): Database = - var err: CBLError - let dbRef = cbl.openDatabase(name, configP, err) - if dbRef == nil: - throw(err) - else: - return Database(handle: dbRef) - -proc openDatabase*(name: string; config: DatabaseConfiguration): Database = - ## Opens a database, or creates it if it doesn't exist yet, returning a new - ## Database instance. The database is closed when this object is - ## garbage-collected, or when you call ``close`` on it.It's OK to open the - ## same database file multiple times. Each Database instance is independent - ## of the others (and must be separately closed.) - var cblConfig = CBLDatabaseConfiguration( - directory: config.directory, - flags: cast[CBLDatabaseFlags](config.flags)) - var cblKey: CBLEncryptionKey - if config.encryptionKey != nil: - cblKey.algorithm = cast[CBLEncryptionAlgorithm]( - config.encryptionKey.algorithm) - cblKey.bytes = config.encryptionKey.bytes - cblConfig.encryptionKey = addr cblKey - return openDB(name, addr cblConfig) - -proc openDatabase*(name: string): Database = - ## Opens or creates a database, using the default configuration. - return openDB(name, nil) - -proc databaseExists*(name: string; inDirectory: string): bool = - ## Returns true if a database with the given name exists in the given - ## directory. - cbl.databaseExists(name, inDirectory) - -proc deleteDatabase*(name: string; inDirectory: string): bool {.discardable.} = - ## Deletes a database file. If the database file is open, an error is - ## returned. - var err: CBLError - if cbl.deleteDatabase(name, inDirectory, err): - return true - elif err.code == 0: - return false - else: - throw(err) - -proc name*(db: Database): string = - ## The database's name (without the ``.cblite2`` extension.) - $(db.handle.name) - -proc path*(db: Database): string = - ## The full path to the database file. - $(db.handle.path) - -proc count*(db: Database): uint64 = - ## The number of documents in the database. (Deleted documents don't count.) - db.handle.count - -proc close*(db: Database) = - ## Closes the database. You must not call this object any more afterwards. - checkBool( (err) => cbl.close(db.handle, err[])) - -proc delete*(db: Database) = - ## Closes and deletes a database. If there are any other open connections to - ## the database, an error is thrown. - checkBool( (err) => cbl.delete(db.handle, err[])) - -proc compact*(db: Database) = - ## Compacts a database file, freeing up disk space. - checkBool( (err) => cbl.compact(db.handle, err[])) - -proc inBatch*(db: Database; fn: proc()) = - ## Performs the callback proc within a batch operation, similar to a - ## transaction. Multiple writes are much faster if done inside a batch. - ## Changes wil not be visible to other Database instances until the batch - ## operaton ends. Batch operations can nest. Changes are not committed until - ## the outer batch ends. - checkBool( (err) => cbl.beginBatch(db.handle, err[])) - defer: checkBool( (err) => cbl.endBatch(db.handle, err[])) - fn() - -proc internal_handle*(db: Database): CBLDatabase = - # INTERNAL ONLY - db.handle - -#TODO: Listeners diff --git a/bindings/nim/src/CouchbaseLite/document.nim b/bindings/nim/src/CouchbaseLite/document.nim deleted file mode 100644 index 97ad7e25..00000000 --- a/bindings/nim/src/CouchbaseLite/document.nim +++ /dev/null @@ -1,264 +0,0 @@ -# Couchbase Lite Document class -# -# Copyright (c) 2020 Couchbase, Inc All rights reserved. -# -# 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 CouchbaseLite/[database, errors, fleece] -import CouchbaseLite/private/cbl - -import options -import sugar - -{.experimental: "notnil".} - - -type Database = database.Database - -type - DocumentObj* {.requiresInit.} = object of RootObj - handle: CBLDocument not nil - db: Option[Database] - Document* = ref DocumentObj - ## An in-memory copy of a document. - ## This object does not allow you to change the document; - ## the subclass ``MutableDocument`` does. - - - MutableDocumentObj* {.requiresInit.} = object of DocumentObj - MutableDocument* = ref MutableDocumentObj - ## An in-memory copy of a document that can be changed and then saved back - ## to the database. - - ConcurrencyControl* {.pure.} = - enum LastWriteWins = 0, FailOnConflict - ## Conflict-handling options when saving or deleting a document. - - SaveConflictHandler* = - proc (documentBeingSaved: MutableDocument; - conflictingDocument: Document): bool - ## Custom conflict handler for use when saving or deleting a document. - ## This handler is called if the save would cause a conflict, i.e. if - ## the document in the database has been updated (probably by a pull - ## replicator, or by application code on another thread) since it was - ## loaded into the Document being saved. - - Timestamp = CBLTimestamp - ## A moment in time, used by the document expiration API. - ## Interpreted as milliseconds since the Unix epoch (Jan 1 1970.) - -proc `=destroy`(d: var DocumentObj) = - release(d.handle) - -proc `=`(dst: var DocumentObj; src: DocumentObj) {.error.} = - echo "(can't copy a Document)" - -proc mustBeInDatabase(doc: Document; db: Database) = - if doc.db != some(db): throw(ErrorCode.InvalidParameter) - -#%%% Database's document-related methods: - -proc getDocument*(db: Database; docID: string): Document = - ## Reads a document from the database, creating a new (immutable) Document - ## object. If you are reading the document in order to make changes to it, - ## call ``getMutableDocument`` instead. - let doc = cbl.getDocument(db.internal_handle, docID) - if doc != nil: - return Document(handle: doc, db: some(db)) - -proc `[]`*(db: Database; docID: string): Document = db.getDocument(docID) - -proc getMutableDocument*(db: Database; docID: string): MutableDocument = - ## Reads a document from the database, in mutable form that can be updated - ## and saved. - let doc = getMutableDocument(db.internal_handle, docID) - if doc != nil: - return MutableDocument(handle: doc, db: some(db)) - -type SaveContext = tuple [doc: MutableDocument; handler: SaveConflictHandler] - -proc saveCallback(context: pointer; documentBeingSaved, - conflictingDocument: CBLDocument): bool = - let ctx = (cast[ptr SaveContext](context))[] - var conflicting: Document = nil - if conflictingDocument != nil: - conflicting = Document(handle: conflictingDocument, db: ctx.doc.db) - return ctx.handler(ctx.doc, conflicting) - -proc saveDocument*(db: Database; doc: MutableDocument; - concurrency: ConcurrencyControl = LastWriteWins): Document {.discardable.} = - ## Saves a (mutable) document to the database. - ## If a conflicting revision has been saved since the document was loaded, - ## the ``concurrency`` parameter specifies whether the save should fail, or - ## the conflicting revision should be overwritten with the revision being - ## saved. If you need finer-grained control, call the version of this method - ## that takes a ``SaveConflictHandler`` instead. - var err: CBLError - let newDoc = db.internal_handle.saveDocument(doc.handle, cast[ - CBLConcurrencyControl](concurrency), err) - if newDoc == nil: - raise mkError(err) - else: - return Document(handle: newDoc, db: some(db)) - -proc saveDocument*(db: Database; doc: MutableDocument; - handler: SaveConflictHandler): Document {.discardable.} = - ## Saves a (mutable) document to the database. - ## If a conflicting revision has been saved since the document was loaded, - ## the callback is called with (a) the document being saved, and (b) the - ## conflicting version already in the database (which may be nil, if the - ## conflict is that the document was deleted.) The callback should make the - ## appropriate changes to the document and return ``true``, or give up and - ## return ``false``, in which case a conflict exception will be thrown. - var context: SaveContext = (doc, handler) - var err: CBLError - let newDoc = db.internal_handle.saveDocumentResolving(doc.handle, - saveCallback, addr context, err) - if newDoc == nil: - throw(err) - else: - return Document(handle: newDoc, db: some(db)) - -proc deleteDocument*(db: Database; doc: Document; - concurrency: ConcurrencyControl = LastWriteWins) {.discardable.} = - ## Deletes a document from the database. Deletions are replicated, so - ## document metadata will be left behind that can later be pushed by the - ## replicator. - doc.mustBeInDatabase(db) - checkBool( (err) => doc.handle.delete(cast[CBLConcurrencyControl]( - concurrency), err[])) - -proc purgeDocument*(db: Database; doc: Document) = - ## Purges a document, removing all traces of the document from the database. - ## Purges are *not* replicated. If the document is changed on a server, it - ## will be re-created when pulled. - doc.mustBeInDatabase(db) - checkBool( (err) => doc.handle.purge(err[])) - -proc purgeDocument*(db: Database; docID: string): bool = - ## Purges a document, removing all traces of the document from the database. - ## Purges are *not* replicated. If the document is changed on a server, it - ## will be re-created when pulled. If no document with this ID exists, - ## returns false. - var err: CBLError - if db.internal_handle.purgeDocumentByID(docID, err): - return true - elif err.code == 0: - return false - else: - throw(err) - -proc getDocumentExpiration*(db: Database; docID: string): Timestamp = - ## Returns the time, if any, at which a given document will expire and be - ## purged. No expiration is indicated by a zero return value. Documents don't - ## normally expire; you have to set an expiration time yourself. - var err: CBLError - let t = db.internal_handle.getDocumentExpiration(docID, err) - if t < 0: throw(err) - return t - -proc setDocumentExpiration*(db: Database; docID: string; - expiration: Timestamp) = - ## Sets a document's expiration time, or clears it if the timestamp is zero. - checkBool( (err) => db.internal_handle.setDocumentExpiration(docID, - expiration, err[])) - - -#%%% Document accessors: - -proc id*(doc: Document): string = - ## The document's ID in the database. - $(doc.handle.id) - -proc revisionID*(doc: Document): string = - ## The document's revision ID, which is a short opaque string that's - ## guaranteed to be unique to every change made to the document. If the - ## document doesn't exist yet, returns an empty string. - $(doc.handle.revisionID) - -proc sequence*(doc: Document): uint64 = - ## Returns a document's current *sequence* in the local database. - ## This number increases every time the document is saved, and a more - ## recently saved document will have a greater sequence number than one saved - ## earlier, so sequences may be used as an abstract 'clock' to tell relative - ## local modification times. - doc.handle.sequence - - -#%%% Document properties: - -proc properties*(doc: Document): Dict = - ## The document's properties, a key/value dictionary. - ## This object is immutable; the subclass ``MutableDocument`` returns a - ## mutable Dict. - doc.handle.properties - -proc `[]`*(doc: Document; key: string): Value = - ## Returns the value of a property. Equivalent to ``doc.properties[key]``. - doc.properties[key] - -proc `[]`*(doc: Document; key: var DictKey): Value = - ## Returns the value of a property. Equivalent to ``doc.properties[key]``. - doc.properties[key] - -proc propertiesAsJSON*(doc: Document): cstring = - ## Returns a document's properties as a JSON string. - ## This can be useful for interoperating with other APIs that can operate on - ## JSON, but be aware that the extra encoding and parsing will hurt - ## performance; it's best to use the Fleece API directly. - doc.handle.propertiesAsJSON - - -#%%% MutableDicument: - -proc mkDoc(doc: CBLDocument): MutableDocument = - if doc == nil: - throw(CBLError(domain: CBLDomain, code: int32( - CBLErrorCode.ErrorMemoryError))) - else: - assert doc.mutableProperties != nil # Make sure it's mutable - return MutableDocument(handle: doc, db: none(Database)) - -proc newDocument*(): MutableDocument = - ## Creates a new, empty document in memory. It will not be added to a - ## database until saved. Its ID will be a randomly-generated UUID. - mkDoc(cbl.newDocument(nil)) - -proc newDocument*(docID: string): MutableDocument = - ## Creates a new, empty document in memory. It will not be added to a - ## database until saved. - mkDoc(cbl.newDocument(docID)) - -proc mutableCopy*(doc: Document): MutableDocument = - ## Creates a new MutableDocument instance that refers to the same document as - ## the original. If the original document is mutable and has unsaved changes, - ## the new one will also start out with the same changes; but mutating one - ## document thereafter will not affect the other. - mkDoc(doc.handle.mutableCopy()) - -proc properties*(doc: MutableDocument): MutableDict = - ## Returns a mutable document's properties as a mutable dictionary. - ## You may modify this dictionary and then call ``Database.saveDocument`` to - ## persist the changes. - wrap(doc.handle.mutableProperties) - -proc `[]=`*(doc: MutableDocument; key: string; value: Settable) = - ## Sets the value of a property. Equivalent to ``doc.properties[key] = - ## value``. - doc.properties[key] = value - -proc `propertiesAsJSON=`*(doc: MutableDocument; json: string) = - ## Sets the document's properties from the JSON string, which must contain an - ## object. - checkBool( (err) => doc.handle.setPropertiesAsJSON(json, err[])) diff --git a/bindings/nim/src/CouchbaseLite/errors.nim b/bindings/nim/src/CouchbaseLite/errors.nim deleted file mode 100644 index 1c01aebd..00000000 --- a/bindings/nim/src/CouchbaseLite/errors.nim +++ /dev/null @@ -1,141 +0,0 @@ -# Couchbase Lite exception classes -# -# Copyright (c) 2020 Couchbase, Inc All rights reserved. -# -# 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 CouchbaseLite/fleece -import CouchbaseLite/private/cbl - -import strformat -import sugar - -{.experimental: "notnil".} - - -type - - ErrorCode* = enum ## Couchbase Lite error codes, found in ``Error`` objects. - AssertionFailed = 1, ## Internal assertion failure - Unimplemented, ## Oops, an unimplemented API call - UnsupportedEncryption, ## Unsupported encryption algorithm - BadRevisionID, ## Invalid revision ID syntax - CorruptRevisionData, ## Revision contains corrupted/unreadable data - NotOpen, ## Database/KeyStore/index is not open - NotFound, ## Document not found - Conflict, ## Document update conflict - InvalidParameter, ## Invalid function parameter or struct value - UnexpectedError, ## Internal unexpected C++ exception - CantOpenFile, ## Database file can't be opened; may not exist - IOError, ## File I/O error - MemoryError, ## Memory allocation failed (out of memory?) - NotWriteable, ## File is not writeable - CorruptData, ## Data is corrupted - Busy, ## Database is busy/locked - NotInTransaction, ## Function must be called while in a transaction - TransactionNotClosed, ## Database can't be closed while a transaction is open - Unsupported, ## Operation not supported in this database - NotADatabaseFile, ## File is not a database, or encryption key is wrong - WrongFormat, ## Database exists but not in the format/storage requested - Crypto, ## Encryption/decryption error - InvalidQuery, ## Invalid query - MissingIndex, ## No such index, or query requires a nonexistent index - InvalidQueryParam, ## Unknown query param name, or param number out of range - RemoteError, ## Unknown error from remote server - DatabaseTooOld, ## Database file format is older than what I can open - DatabaseTooNew, ## Database file format is newer than what I can open - BadDocID, ## Invalid document ID - CantUpgradeDatabase ## DB can't be upgraded (might be unsupported dev version) - - NetworkErrorCode* = enum ## Network error codes, found in ``NetworkError`` objects. - DNSFailure = 1, ## DNS lookup failed - UnknownHost, ## DNS server doesn't know the hostname - Timeout, ## No response received before timeout - InvalidURL, ## Invalid URL - TooManyRedirects, ## HTTP redirect loop - TLSHandshakeFailed, ## Low-level error establishing TLS - TLSCertExpired, ## Server's TLS certificate has expired - TLSCertUntrusted, ## Cert isn't trusted for other reason - TLSClientCertRequired, ## Server requires client to have a TLS certificate - TLSClientCertRejected, ## Server rejected my TLS client certificate - TLSCertUnknownRoot, ## Self-signed cert, or unknown anchor cert - InvalidRedirect, ## Attempted redirect to invalid URL - Unknown, ## Unknown networking error - TLSCertRevoked, ## Server's cert has been revoked - TLSCertNameMismatch ## Server cert's name does not match DNS name - -type - Error* = ref object of CatchableError - ## Base class for Couchbase Lite exceptions. - cblErr: CBLError - CouchbaseLiteError* = ref object of Error - ## A Couchbase Lite-defined error. See its ``code`` for details. - code*: ErrorCode - POSIXError* = ref object of Error - ## An OS error. See the ``errno`` property for the specific error (defined - ## in ````) - errno*: int - SQLiteError* = ref object of Error - ## A SQLite database error. The ``code`` is defined in ``sqlite3.h``. - code*: int - FleeceError* = ref object of Error - ## A Fleece error. - code*: FleeceErrorCode - NetworkError* = ref object of Error - ## A Couchbase Lite network-related error; see the ``code`` for details. - code*: NetworkErrorCode - WebSocketError* = ref object of Error - ## An HTTP or WebSocket error. The ``code`` is an HTTP status if less than - ## 1000, else a WebSocket status. - code*: int - -proc message*(err: Error): string = $(message(err.cblErr)) - ## Gets the message associated with an error. - -proc codeStr*(err: Error): string = - ## Returns the name of the error's code. - case err.cblErr.domain: - of CBLDomain: $(cast[CBLErrorCode](err.cblErr.code)) - of FleeceDomain: $(cast[FleeceErrorCode](err.cblErr.code)) - of NetworkDomain: $(cast[NetworkErrorCode](err.cblErr.code)) - else: &"{err.cblErr.code}" - -proc `$`*(err: Error): string = - ## Formats an Error as a string, including the message, type and code. - &"{err.message} ({err.cblErr.domain}.{err.cblErr.code}: {err.codeStr})" - -#%%%% Internal error handling utilities: - -# TODO: Avoid making these public - -proc mkError*(err: CBLError): Error = - case err.domain: - of CBLDomain: CouchbaseLiteError(cblErr: err, code: ErrorCode(err.code)) - of POSIXDomain: POSIXError(cblErr: err, errno: err.code) - of SQLiteDomain: SQLiteError(cblErr: err, code: err.code) - of FleeceDomain: FleeceError(cblErr: err, code: FleeceErrorCode(err.code)) - of NetworkDomain: NetworkError(cblErr: err, code: NetworkErrorCode(err.code)) - of WebSocketDomain: WebSocketError(cblErr: err, code: err.code) - else: CouchbaseLiteError(cblErr: err, code: ErrorCode(UnexpectedError)) - -proc throw*(err: CBLError) {.noreturn.} = - raise mkError(err) - -proc throw*(code: ErrorCode) = - throw(CBLError(domain: cbl.CBLDomain, code: int32(code))) - -proc checkBool*(fn: (ptr CBLError) -> bool) = - var err: CBLError - if not fn(addr err): - throw(err) diff --git a/bindings/nim/src/CouchbaseLite/fleece.nim b/bindings/nim/src/CouchbaseLite/fleece.nim deleted file mode 100644 index bea7753b..00000000 --- a/bindings/nim/src/CouchbaseLite/fleece.nim +++ /dev/null @@ -1,395 +0,0 @@ -# Fleece, a JSON-like structured storage format -- https://github.com/couchbaselabs/fleece -# -# Copyright (c) 2020 Couchbase, Inc All rights reserved. -# -# 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 CouchbaseLite/private/fl - - -## This is a Nim binding for the Fleece binary encoding format. -## Fleece documentation is here: https://github.com/couchbaselabs/fleece/wiki -## "Using Fleece" is the best starting point. - -#TODO: Encoder -#TODO: DeepIterator -#TODO: JSON-Delta - - -#======== TYPES - - -type FleeceErrorCode* = enum - ## Types of Fleece errors. - MemoryError = 1, ## Out of memory, or allocation failed - OutOfRange, ## Array index or iterator out of range - InvalidData, ## Bad input data (NaN, non-string key, etc.) - EncodeError, ## Structural error encoding (missing value, too many ends, etc.) - JSONError, ## Error parsing JSON - UnknownValue, ## Unparseable data in a Value (corrupt? Or from some distant future?) - InternalError, ## Something that shouldn't happen - NotFound, ## Key not found - SharedKeysStateError, ## Misuse of shared keys (not in transaction, etc.) - POSIXError, ## POSIX API call failed - Unsupported ## Operation is unsupported - -type FleeceError* = ref object of CatchableError - ## Exception thrown by Fleece functions. - code*: FleeceErrorCode - -proc throw(flCode: FLError; msg: string) = - let code = cast[FleeceErrorCode](flCode) - raise FleeceError(code: code, msg: (if msg != "": msg else: $code)) - - -type - Value* = FLValue ## A value of any type (JSON types or raw data.) May also be null/undefined. - Array* = FLArray ## An array Value (unless empty/undefined) - Dict* = FLDict ## A dictionary/map/object Value (unless empty/undefined) - - Slot* = FLSlot ## Temporary reference to a settable value in a collection - - MutableArray* = object - ## A mutable, heap-based 'subclass' of Array. - mval: FLMutableArray - MutableDict* = object - ## A mutable, heap-based 'subclass' of Dict. - mval: FLMutableDict - - ArrayObject* = Array | MutableArray - DictObject* = Dict | MutableDict - ImmutableObject* = Value | Array | Dict - MutableObject* = MutableArray | MutableDict - FleeceObject* = ImmutableObject | MutableObject - - Settable* = bool | int64 | uint64 | cfloat | cdouble | string | openarray[ - uint8] | FleeceObject - - -#======== FLEECE DOCUMENT - - -type Fleece* = object - ## A container that holds Fleece-encoded data and exposes its object tree. - doc: FLDoc - -proc `=`(self: var Fleece; other: Fleece) = - if self.doc != other.doc: - release(self.doc) - self.doc = other.doc - discard retain(self.doc) - -proc `=destroy`(self: var Fleece) = - release(self.doc) - - -type Trust* = enum - ## Whether to trust that encoded Fleece data is valid - untrusted, ## Data is untrusted; will be validated during parse (safer!) - trusted ## Data is trusted, most validation skipped (faster) - -proc parse*(data: openarray[byte]; trust: Trust = untrusted): Fleece = - ## Parses Fleece-encoded data, producing a Fleece object. - let flData = asSlice(data).copy() - let doc = fl.newDocFromResultData(flData, FLTrust(trust), nil, FLSlice()) - if doc == nil: throw(FLError.InvalidData, "Invalid Fleece data") - return Fleece(doc: doc) - -proc parseJSON*(json: string): Fleece = - ## Parses JSON data, producing a Fleece object. (JSON is always assumed - ## untrusted and will be validated. Errors cause exceptions.) - var err: FLError - let doc = fl.newDocFromJSON(asSlice(json), err) - if doc == nil: throw(err, "Invalid JSON") - return Fleece(doc: doc) - -proc root*(self: Fleece): Value = - ## The root object. This reference and all children are only valid as long as - ## this ``Fleece`` object is. - if self.doc == nil: nil else: self.doc.getRoot() -proc asArray*(self: Fleece): Array = - ## The root array, or an empty/undefined value if the root is not an Array. - ## This reference and all children are only valid as long as this ``Fleece`` - ## object is. - self.root.asArray() -proc asDict*(self: Fleece): Dict = - ## The root dictionary, or an empty/undefined value if the root is not a Dict. - ## This reference and all children are only valid as long as this ``Fleece`` - ## object is. - self.root.asDict() - - -#======== VALUE - - -proc asValue*(v: ImmutableObject): Value = cast[Value](v) -proc asValue*(a: MutableArray): Value = cast[Value](a.mval) -proc asValue*(d: MutableDict): Value = cast[Value](d.mval) - -type - Type* = enum undefined = -1, null, bool, number, string, data, array, dict - Timestamp* = FLTimestamp - -proc type*(v: Value): Type = Type(fl.getType(v)) - -proc isNumber*(v: Value): bool = v.type == Type.number -proc isInt*(v: Value): bool = fl.isInteger(v) -proc isFloat*(v: Value): bool = v.isNumber and not v.isInt -proc isString*(v: Value): bool = v.type == Type.string - -proc asInt*[T](v: Value; dflt: T): T = - if not v.isNumber: return dflt - let i = fl.asInt(v) - try: - return T(i) - except RangeError: - return if i >= 0: high(T) else: low(T) - -proc asBool*(v: Value): bool = fl.asBool(v) -proc asInt64*(v: Value): int64 = fl.asInt(v) -proc asInt*(v: Value): int = v.asInt(0) -proc asFloat*(v: Value): float = fl.asDouble(v) -proc asString*(v: Value): string = fl.asString(v).toString() -proc asData*(v: Value): seq[uint8] = fl.asData(v).toByteArray() -proc asTimestamp*(v: Value): Timestamp = fl.asTimestamp(v) - -proc asBool*(v: Value; dflt: bool): bool = - if v.type == Type.bool: fl.asBool(v) else: dflt -proc asFloat*(v: Value; dflt: float): float = - if v.isNumber: v.asFloat else: dflt -proc asString*(v: Value; dflt: string): string = - if v.isString: v.asString else: dflt -proc asTimestamp*(v: Value; dflt: Timestamp): Timestamp = - let t = fl.asTimestamp(v) - if ord(t) > 0: t else: dflt - -proc `==`*(v: Value; n: int64): bool = v.isInt and v.asInt == n -proc `==`*(v: Value; n: float64): bool = v.isNumber and v.asFloat == n -proc `==`*(v: Value; str: string): bool = v.isString and v.asString == str - -type - ToJSONFlag* = enum JSON5, canonical - ToJSONFlags* = set[ToJSONFlag] - -proc toJSON*(v: FleeceObject; flags: ToJSONFlags = {}): string = - ## Converts any value to a JSON string. Returns "undefined" if the value is - ## undefined. - fl.toJSONX(v.asValue, ToJSONFlag.JSON5 in flags, ToJSONFlag.canonical in - flags).toString() - -proc `$`*(v: FleeceObject): string = toJSON(v, {}) - -#======== ARRAY - -proc asArray*(a: Array): Array = a -proc asArray*(a: MutableArray): Array = cast[Array](a.mval) -proc asArray*(v: Value): Array = fl.asArray(v) - -proc len*(a: ArrayObject): uint32 = fl.count(a.asArray) -proc isEmpty*(a: ArrayObject): bool = fl.isEmpty(a.asArray) -proc get*(a: ArrayObject; i: uint32): Value = fl.get(a.asArray, i) - -proc `[]`*(a: Array; i: uint32): Value = a.get(i) -proc `[]`*(v: Value; i: uint32): Value = v.asArray[i] -proc `[]`*(f: Fleece; i: uint32): Value = f.asArray[i] - -iterator items*(a: ArrayObject): Value = - ## Array iterator. - var i: FLArrayIterator - a.asArray.begin(addr i) - while true: - let v = getValue(addr i) - if v == nil: break - yield v - if not next(addr i): break - - -#======== DICT - -proc asDict*(d: Dict): Dict = d -proc asDict*(d: MutableDict): Dict = cast[Dict](d.mval) -proc asDict*(v: Value): Dict = fl.asDict(v) - -proc len*(d: DictObject): uint32 = fl.count(d.asDict) -proc isEmpty*(d: DictObject): bool = fl.isEmpty(d.asDict) -proc get*(d: DictObject; key: string): Value = fl.get(d.asDict, key.asSlice) - -proc `[]`*(d: DictObject; key: string): Value = d.get(key) -proc `[]`*(v: Value; key: string): Value = v.asDict[key] -proc `[]`*(f: Fleece; key: string): Value = f.asDict[key] - -iterator items*(d: DictObject): tuple [key: string; value: Value] = - ## Dict iterator. - var i: FLDictIterator - d.asDict.begin(addr i) - while true: - let v = getValue(addr i) - if v == nil: break - let k = getKeyString(addr i).toString() - yield (k, v) - if not next(addr i): break - - -type DictKey* {.requiresInit.} = object - ## A DictKey is a cached dictionary key. It works just like a string, but it's - ## faster because it can cache the internal representation of the key. - ## DictKey instances have to be created by the ``dictKey`` function. - flkey: FLDictKey - -proc dictKey*(key: string): DictKey = - ## Creates a DictKey representing the given string. - DictKey(flkey: fl.init(key.asSlice())) - -proc `$`*(key: var DictKey): string = - fl.getString(addr key.flkey).toString - -proc get*(d: DictObject; key: var DictKey): Value = - fl.getWithKey(d.asDict, addr key.flkey) - -proc `[]`*(d: DictObject; key: var DictKey): Value = d.asDict.get(key) -proc `[]`*(v: Value; key: var DictKey): Value = v.asDict[key] -proc `[]`*(f: Fleece; key: var DictKey): Value = f.asDict[key] - - -type KeyPath* {.requiresInit.} = object - ## KeyPath is like a multi-level DictKey: it's initialized with a path string - ## like "coords.lat" or "contacts[2].lastName" and can then be used like a key - ## to access the value at that path in any object. If any component in the - ## path is missing, the result is a null/undefined Value. - handle: FLKeyPath - -proc `=`(self: var KeyPath; other: KeyPath) {.error.} = - free(self.handle) - self.handle = other.handle - -proc `=destroy`(self: var KeyPath) = - free(self.handle) - -proc keyPath*(path: string): KeyPath = - ## Creates a new KeyPath from a path string like "coords.lat" or - ## "contacts[2].lastName". Throws an exception if the path syntax is invalid. - var err: FLError - let h = fl.newKeyPath(path.asSlice(), err) - if h == nil: throw(err, "Invalid KeyPath") - return KeyPath(handle: h) - -proc eval*(path: KeyPath; v: Value): Value = - path.handle.eval(v) - - -#======== MUTABLE ARRAY - - -type - CopyFlag = enum ## Options for making (mutable) copies of Fleece values. - deepCopy, ## Copy the entire object tree from here - copyImmutables ## Even copy immutable values from Fleece data - CopyFlags = set[CopyFlag] - -proc `=`(self: var MutableArray; other: MutableArray) = - if self.mval != other.mval: - release(self.mval) - self.mval = other.mval - discard retain(self.mval) - -proc `=destroy`(self: var MutableArray) = - release(self.mval) - -proc newMutableArray*(): MutableArray = - ## Creates an empty mutable array. Unlike the immutable values that point into - ## Fleece-formatted data, this object is not dependent on a container and - ## stays valid as long as you have a reference to it. - MutableArray(mval: fl.newMutableArray()) - -proc mutableCopy*(a: Array; flags: CopyFlags = {}): MutableArray = - ## Makes a mutable copy of an array. - MutableArray(mval: a.mutableCopy(cast[fl.CopyFlags](flags))) - -proc wrap*(a: FLMutableArray): MutableArray = - MutableArray(mval: retain(a)) - -proc source*(a: MutableArray): Array = - ## If this is a mutable copy of an immutable Array, returns the original. - a.mval.getSource() -proc isChanged*(a: MutableArray): bool = - ## Returns true if this array has been modified since created. - a.mval.isChanged() - -# (extra stuff for Slot to enable use of the Settable type) -proc set(s: Slot; v: string) = set(s, v.asSlice()) -proc set(s: Slot; v: openarray[uint8]) = setData(s, v.asSlice()) -proc set(s: Slot; v: FleeceObject) = set(s, v.asValue()) - -proc set*(a: MutableArray; index: uint32; value: Settable) = - ## Stores a value at an existing (zero-based) index in a mutable array. - a.mval.set(index).set(value) -proc `[]=`*(a: MutableArray; index: uint32; value: Settable) = - ## Stores a value at an existing (zero-based) index in a mutable array. - a.mval.set(index).set(value) -proc insert*(a: MutableArray; value: Settable; index: uint32) = - ## Inserts a value at a (zero-based) index in a mutable array. - ## Any items at that index and higher are pushed up by one. - a.mval.insert(index).set(value) -proc add*(a: MutableArray; value: Settable) = - ## Appends a value to the end of a mutable array. - a.mval.append().set(value) -proc delete*(a: MutableArray; index: uint32) = - ## Removes a value from a mutable array. Any items at higher indexes move down - ## one. - a.mval.remove(index, 1) - - -#======== MUTABLE DICT - - -proc `=`(self: var MutableDict; other: MutableDict) = - if self.mval != other.mval: - release(self.mval) - self.mval = other.mval - discard retain(self.mval) - -proc `=destroy`(self: var MutableDict) = - release(self.mval) - -proc newMutableDict*(): MutableDict = - ## Creates an empty mutable dictionary. Unlike the immutable values that point - ## into Fleece-formatted data, this object is not dependent on a container and - ## stays valid as long as you have a reference to it. - MutableDict(mval: fl.newMutableDict()) - -proc mutableCopy*(d: Dict; flags: CopyFlags = {}): MutableDict = - ## Makes a mutable copy of a dictionary. - MutableDict(mval: d.mutableCopy(cast[fl.CopyFlags](flags))) - -proc wrap*(d: FLMutableDict): MutableDict = - MutableDict(mval: retain(d)) - -proc source*(d: MutableDict): Dict = - ## If this is a mutable copy of an immutable Dict, returns the original. - d.mval.getSource() -proc isChanged*(d: MutableDict): bool = - ## Returns true if this array has been modified since created. - d.mval.isChanged() - -proc set*(d: MutableDict; key: string; value: Settable) = - ## Stores a value for a key in a mutable dictionary. - ## Any prior value for that key is replaced. - d.mval.set(key.asSlice()).set(value) -proc `[]=`*(d: MutableDict; key: string; value: Settable) = - ## Stores a value for a key in a mutable dictionary. - ## Any prior value for that key is replaced. - d.mval.set(key.asSlice()).set(value) -proc delete*(d: MutableDict; key: string) = - ## Removes the value, if any, for a key in a mutable dictionary. - d.mval.remove(key.asSlice()) diff --git a/bindings/nim/src/CouchbaseLite/listener.nim b/bindings/nim/src/CouchbaseLite/listener.nim deleted file mode 100644 index 9315a0f1..00000000 --- a/bindings/nim/src/CouchbaseLite/listener.nim +++ /dev/null @@ -1,33 +0,0 @@ -# Couchbase Lite listener token -# -# Copyright (c) 2020 Couchbase, Inc All rights reserved. -# -# 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 CouchbaseLite/private/cbl - -{.experimental: "notnil".} - - -type - ListenerToken* = object - ## A reference to a registered listener callback. When this object goes out - ## of scope, the listener is removed and the callback will no longer be - ## called. - handle: CBLListenerToken not nil - -proc `=destroy`(t: var ListenerToken) = - remove(t.handle) - -proc `=`(dst: var ListenerToken, src: ListenerToken) {.error.} diff --git a/bindings/nim/src/CouchbaseLite/private/cbl.c2nim b/bindings/nim/src/CouchbaseLite/private/cbl.c2nim deleted file mode 100644 index 63805820..00000000 --- a/bindings/nim/src/CouchbaseLite/private/cbl.c2nim +++ /dev/null @@ -1,55 +0,0 @@ -// Definitions for c2nim to parse CouchbaseLite headers - -#skipinclude -//#skipcomments - -#def FLPURE -#def FLAPI -#def FLNONNULL -#assumendef FL_IMPL -#assumendef DOXYGEN_PARSING -#assumendef CMAKE -#assumendef __OBJC__ -#assumedef FL_BINDING - -#def CBL_CORE_API -#def CBLAPI -#def CBL_ENUM(_type, _name) enum _name _name; enum _name -#def CBL_OPTIONS(_type, _name) enum _name _name; enum _name -#def CBLINLINE -#def _cbl_nonnull -#def _cbl_returns_nonnull -#def _cbl_warn_unused -#def __printflike(fmtarg, firstvararg) -#def CBL_REFCOUNTED(TYPE,NAME) - -#assumedef CBL_BINDING -#assumendef COUCHBASE_ENTERPRISE - - -// Exceptions to name mangling: -#mangle CBLDomain CBLDomain - -// CBL Name mangling: -#mangle "^'CBL'{[A-Z][a-zA-Z]*}'_New'" "New$1" -#mangle "^'CBL'{[A-Z][a-zA-Z]*}'_Create'" "Create$1" -#mangle "^'CBL'{[A-Z][a-zA-Z]*}'_Open'$" "Open$1" -#mangle "^'CBL'{[A-Z][a-zA-Z]*}'_Get'$" "Get$1" -#mangle "^'CBL'[A-Z][a-zA-Z]*'_'{.*}" "$1" - -#mangle "^'CBL_'{[a-z]*}" "$1" -#mangle "^'CBL'{[a-z]*}" "$1" -#mangle "^'kCBL'{[a-z]*}" "k$1" - -// Fleece name mangling: -#mangle "^'FL'{[A-Z][a-zA-Z]*}'_New'" "New$1" -#mangle "^'FL'{[A-Z][a-zA-Z]*}'_Create'" "Create$1" -#mangle "^'FL'{[A-Z][a-zA-Z]*}'_New'$" "Open$1" -#mangle "^'FL'[A-Z][a-zA-Z]*'_'{.*}" "$1" - -#mangle "^'FL_'{[a-z]*}" "$1" -#mangle "^'FL'{[a-z]*}" "$1" -#mangle "^'kFL'{[a-z]*}" "k$1" - -# Nim does not allow leading underscores in identifiers -#mangle "^'_'{.*}" "Internal$1" \ No newline at end of file diff --git a/bindings/nim/src/CouchbaseLite/private/cbl.nim b/bindings/nim/src/CouchbaseLite/private/cbl.nim deleted file mode 100644 index 52bc4be8..00000000 --- a/bindings/nim/src/CouchbaseLite/private/cbl.nim +++ /dev/null @@ -1,1421 +0,0 @@ -## *** NOTE: DO NOT MACHINE-UPDATE THIS FILE *** -## -## This started out as a machine-generated file (produced by `gen-bindings.sh`), -## but it has been hand-edited to fix issues that kept it from compiling. -## -## If you run the script again, it will generate a _new_ file `CouchbaseLite-new.nim`. -## You'll need to merge new/changed declarations from that file into this one, by hand. -## -## Status: Up-to-date as of 5 May 2020, commit 036cd9f7 "Export kCBLAuthDefaultCookieName...", -## except I've left out the new "_s"-suffixed alternate functions, which Nim doesn't need. - - -when defined(Linux): - {.push dynlib: "libcblite.so".} -elif defined(MacOS) or defined(MacOSX): - {.push dynlib: "libcblite.dylib".} -elif defined(Windows): - {.push dynlib: "cblite.dll".} - - -## -## CBLBase.h -## -## Copyright (c) 2018 Couchbase, Inc All rights reserved. -## -## 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 fl - -## \defgroup errors Errors -## Types and constants for communicating errors from API calls. -## CBLError domains, serving as namespaces for numeric error codes. -type - CBLErrorDomain* {.size: sizeof(cint).} = enum - CBLDomain = 1, ## code is a Couchbase Lite error code; see \ref CBLErrorCode - POSIXDomain, ## code is a POSIX `errno`; see "errno.h" - SQLiteDomain, ## code is a SQLite error; see "sqlite3.h" - FleeceDomain, ## code is a Fleece error; see "FleeceException.h" - NetworkDomain, ## code is a network error; see \ref CBLNetworkErrorCode - WebSocketDomain, ## code is a WebSocket close code (1000...1015) or HTTP error (300..599) - MaxErrorDomainPlus1 - - -## Couchbase Lite error codes, in the CBLDomain. -type - CBLErrorCode* {.size: sizeof(cint).} = enum - ErrorAssertionFailed = 1, ## Internal assertion failure - ErrorUnimplemented, ## Oops, an unimplemented API call - ErrorUnsupportedEncryption, ## Unsupported encryption algorithm - ErrorBadRevisionID, ## Invalid revision ID syntax - ErrorCorruptRevisionData, ## Revision contains corrupted/unreadable data - ErrorNotOpen, ## CBLDatabase/KeyStore/index is not open - ErrorNotFound, ## CBLDocument not found - ErrorConflict, ## CBLDocument update conflict - ErrorInvalidParameter, ## Invalid function parameter or struct value - ErrorUnexpectedError, ## Internal unexpected C++ exception - ErrorCantOpenFile, ## CBLDatabase file can't be opened; may not exist - ErrorIOError, ## File I/O error - ErrorMemoryError, ## Memory allocation failed (out of memory?) - ErrorNotWriteable, ## File is not writeable - ErrorCorruptData, ## Data is corrupted - ErrorBusy, ## CBLDatabase is busy/locked - ErrorNotInTransaction, ## Function must be called while in a transaction - ErrorTransactionNotClosed, ## CBLDatabase can't be closed while a transaction is open - ErrorUnsupported, ## Operation not supported in this database - ErrorNotADatabaseFile, ## File is not a database, or encryption key is wrong - ErrorWrongFormat, ## CBLDatabase exists but not in the format/storage requested - ErrorCrypto, ## Encryption/decryption error - ErrorInvalidQuery, ## Invalid query - ErrorMissingIndex, ## No such index, or query requires a nonexistent index - ErrorInvalidQueryParam, ## Unknown query param name, or param number out of range - ErrorRemoteError, ## Unknown error from remote server - ErrorDatabaseTooOld, ## CBLDatabase file format is older than what I can open - ErrorDatabaseTooNew, ## CBLDatabase file format is newer than what I can open - ErrorBadDocID, ## Invalid document ID - ErrorCantUpgradeDatabase, ## DB can't be upgraded (might be unsupported dev version) - NumErrorCodesPlus1 - - -## Network error codes, in the CBLNetworkDomain. -type - NetworkErrorCode* {.size: sizeof(cint).} = enum - NetErrDNSFailure = 1, ## DNS lookup failed - NetErrUnknownHost, ## DNS server doesn't know the hostname - NetErrTimeout, ## No response received before timeout - NetErrInvalidURL, ## Invalid URL - NetErrTooManyRedirects, ## HTTP redirect loop - NetErrTLSHandshakeFailed, ## Low-level error establishing TLS - NetErrTLSCertExpired, ## Server's TLS certificate has expired - NetErrTLSCertUntrusted, ## Cert isn't trusted for other reason - NetErrTLSClientCertRequired, ## Server requires client to have a TLS certificate - NetErrTLSClientCertRejected, ## Server rejected my TLS client certificate - NetErrTLSCertUnknownRoot, ## Self-signed cert, or unknown anchor cert - NetErrInvalidRedirect, ## Attempted redirect to invalid URL - NetErrUnknown, ## Unknown networking error - NetErrTLSCertRevoked, ## Server's cert has been revoked - NetErrTLSCertNameMismatch ## Server cert's name does not match DNS name - - -## A struct holding information about an error. It's declared on the stack by a caller, and -## its address is passed to an API function. If the function's return value indicates that -## there was an error (usually by returning NULL or false), then the CBLError will have been -## filled in with the details. -type - CBLError* {.byref.} = object - domain*: CBLErrorDomain ## Domain of errors; a namespace for the `code`. - code*: int32 ## CBLError code, specific to the domain. 0 always means no error. - internalInfo: int32 - - -## Returns a message describing an error. -proc message*(err: var CBLError): cstring {.importc: "CBLError_Message".} -proc message_s*(err: var CBLError): FLSliceResult {. - importc: "CBLError_Message_s".} - - -## \defgroup other_types Other Types -## A date/time representation used for document expiration (and in date/time queries.) -## Measured in milliseconds since the Unix epoch (1/1/1970, midnight UTC.) -type - CBLTimestamp* = int64 - -## Returns the current time, in milliseconds since 1/1/1970. -proc now*(): CBLTimestamp {.importc: "CBL_Now".} - -## \defgroup refcounting Reference Counting -## Couchbase Lite "objects" are reference-counted; the functions below are the shared -## _retain_ and _release_ operations. (But there are type-safe equivalents defined for each -## class, so you can call \ref CBLDatabase_Release() on a database, for instance, without having to -## type-cast.) -## -## API functions that **create** a ref-counted object (typically named `..._New()` or `..._Create()`) -## return the object with a ref-count of 1; you are responsible for releasing the reference -## when you're done with it, or the object will be leaked. -## -## Other functions that return an **existing** ref-counted object do not modify its ref-count. -## You do _not_ need to release such a reference. But if you're keeping a reference to the object -## for a while, you should retain the reference to ensure it stays alive, and then release it when -## finished (to balance the retain.) -## -type - CBLRefCounted = ptr object - -proc retain(a1: CBLRefCounted): CBLRefCounted {.importc: "CBL_Retain", discardable.} -proc release(a1: CBLRefCounted) {.importc: "CBL_Release".} - -## Returns the total number of Couchbase Lite objects. Useful for leak checking. -proc instanceCount*(): cuint {.importc: "CBL_InstanceCount".} - -## Logs the class and address of each Couchbase Lite object. Useful for leak checking. -proc dumpInstances*() {.importc: "CBL_DumpInstances".} - -## \defgroup database CBLDatabase -## A connection to an open database. -type - CBLDatabase* = ptr object - -proc retain*(obj: CBLDatabase): CBLDatabase {.inline, discardable.} = - retain(cast[CBLRefCounted](obj)) - return obj -proc release*(obj: CBLDatabase) {.inline.} = - release(cast[CBLRefCounted](obj)) - - -## \defgroup documents Documents -## An in-memory copy of a document. -## CBLDocument objects can be mutable or immutable. Immutable objects are referenced by _const_ -## pointers; mutable ones by _non-const_ pointers. This prevents you from accidentally calling -## a mutable-document function on an immutable document. -type - CBLDocument* = ptr object - -proc retain*(obj: CBLDocument): CBLDocument {.inline, discardable.} = - retain(cast[CBLRefCounted](obj)) - return obj -proc release*(obj: CBLDocument) {.inline.} = - release(cast[CBLRefCounted](obj)) - -## \defgroup blobs Blobs -## A binary data value associated with a \ref CBLDocument. -type - CBLBlob* = ptr object - -proc retain*(obj: CBLBlob): CBLBlob {.inline, discardable.} = - retain(cast[CBLRefCounted](obj)) - return obj -proc release*(obj: CBLBlob) {.inline.} = - release(cast[CBLRefCounted](obj)) - -## \defgroup queries Queries -## A compiled database query. -type - CBLQuery* = ptr object - -proc retain*(obj: CBLQuery): CBLQuery {.inline, discardable.} = - retain(cast[CBLRefCounted](obj)) - return obj -proc release*(obj: CBLQuery) {.inline.} = - release(cast[CBLRefCounted](obj)) - -## An iterator over the rows resulting from running a query. -type - CBLResultSet* = ptr object - -proc retain*(obj: CBLResultSet): CBLResultSet {.inline, discardable.} = - retain(cast[CBLRefCounted](obj)) - return obj -proc release*(obj: CBLResultSet) {.inline.} = - release(cast[CBLRefCounted](obj)) - -## \defgroup replication Replication -## A background task that syncs a \ref CBLDatabase with a remote server or peer. -type - CBLReplicator* = ptr object - -proc retain*(obj: CBLReplicator): CBLReplicator {.inline, discardable.} = - retain(cast[CBLRefCounted](obj)) - return obj -proc release*(obj: CBLReplicator) {.inline.} = - release(cast[CBLRefCounted](obj)) - -## \defgroup listeners Listeners -## Every API function that registers a listener callback returns an opaque token representing -## the registered callback. To unregister any type of listener, call \ref CBLListener_Remove. -## -## The steps to creating a listener are: -## 1. Define the type of contextual information the callback needs. This is usually one of -## your objects, or a custom struct. -## 2. Implement the listener function: -## - The parameters and return value must match the callback defined in the API. -## - The first parameter is always a `void*` that points to your contextual -## information, so cast that to the actual pointer type. -## - **The function may be called on a background thread!** And since the CBL API is not itself -## thread-safe, you'll need to take special precautions if you want to call the API -## from your listener, such as protecting all of your calls (inside and outside the -## listener) with a mutex. It's safer to use \ref CBLDatabase_BufferNotifications to -## schedule listener callbacks to a time of your own choosing, such as your thread's -## event loop; see that function's docs for details. -## 3. To register the listener, call the relevant `AddListener` function. -## - The parameters will include the CBL object to observe, the address of your listener -## function, and a pointer to the contextual information. (That pointer needs to remain -## valid for as long as the listener is registered, so it can't be a pointer to a local -## variable.) -## - The return value is a \ref CBLListenerToken pointer; save that. -## 4. To unregister the listener, pass the \ref CBLListenerToken to \ref CBLListener_Remove. -## - You **must** unregister the listener before the contextual information pointer is -## invalidated, e.g. before freeing the object it points to. -## -## An opaque 'cookie' representing a registered listener callback. -## It's returned from functions that register listeners, and used to remove a listener by -## calling \ref CBLListener_Remove. -type - CBLListenerToken* = ptr object - -## Removes a listener callback, given the token that was returned when it was added. -proc remove*(a1: CBLListenerToken) {.importc: "CBLListener_Remove".} - - - - -## -## CBLLog.h -## -## Copyright © 2019 Couchbase. All rights reserved. -## -## 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. -## - -## * \defgroup logging Logging -## Managing messages that Couchbase Lite logs at runtime. -## * Subsystems that log information. - - - -type - CBLLogDomain* {.size: sizeof(cint).} = enum - kLogDomainAll, kLogDomainDatabase, kLogDomainQuery, kLogDomainReplicator, kLogDomainNetwork - -## * Levels of log messages. Higher values are more important/severe. Each level includes the lower ones. -type - CBLLogLevel* {.size: sizeof(cint).} = enum - CBLLogDebug, ## /< Extremely detailed messages, only written by debug builds of CBL. - CBLLogVerbose, ## /< Detailed messages about normally-unimportant stuff. - CBLLogInfo, ## /< Messages about ordinary behavior. - CBLLogWarning, ## /< Messages warning about unlikely and possibly bad stuff. - CBLLogError, ## /< Messages about errors - CBLLogNone ## /< Disables logging entirely. - - -## * Formats and writes a message to the log, in the given domain at the given level. -## \warning This function takes a `printf`-style format string, with extra parameters to match the format placeholders, and has the same security vulnerabilities as other `printf`-style functions. -## If you are logging a fixed string, call \ref CBL_Log_s instead, otherwise any `%` characters in the -## `format` string will be misinterpreted as placeholders and the dreaded Undefined Behavior will result, -## possibly including crashes or overwriting the stack. -## @param domain The log domain to associate this message with. -## @param level The severity of the message. If this is lower than the current minimum level for the domain -## (as set by \ref CBL_SetLogLevel), nothing is logged. -## @param format A `printf`-style format string. `%` characters in this string introduce parameters, -## and corresponding arguments must follow. -proc log*(domain: CBLLogDomain; level: CBLLogLevel; format: cstring) {.varargs, - importc: "CBL_Log".} - -## * Writes a pre-formatted message to the log, exactly as given. -## @param domain The log domain to associate this message with. -## @param level The severity of the message. If this is lower than the current minimum level for the domain -## (as set by \ref CBL_SetLogLevel), nothing is logged. -## @param message The exact message to write to the log. - -proc logString*(domain: CBLLogDomain; level: CBLLogLevel; message: Slice) {. - importc: "CBL_Log_s".} -## * \name Console Logging and Custom Logging -## * A logging callback that the application can register. -## @param domain The domain of the message; \ref kCBLLogDomainAll if it doesn't fall into a specific domain. -## @param level The severity level of the message. -## @param message The actual formatted message. - -type - CBLLogCallback* = proc (domain: CBLLogDomain; level: CBLLogLevel; - message: cstring) - -## * Gets the current log level for debug console logging. -## Only messages at this level or higher will be logged to the console or callback. -proc consoleLevel*(): CBLLogLevel {.importc: "CBLLog_ConsoleLevel".} - -## * Sets the detail level of logging. -## Only messages whose level is ≥ the given level will be logged to the console or callback. -proc setConsoleLevel*(a1: CBLLogLevel) {.importc: "CBLLog_SetConsoleLevel".} - -## * Returns true if a message with the given domain and level would be logged to the console. -proc willLogToConsole*(domain: CBLLogDomain; level: CBLLogLevel): bool {. - importc: "CBLLog_WillLogToConsole".} - -## * Gets the current log callback. -proc callback*(): CBLLogCallback {.importc: "CBLLog_Callback".} - -## * Sets the callback for receiving log messages. If set to NULL, no messages are logged to the console. -proc setCallback*(a1: CBLLogCallback) {.importc: "CBLLog_SetCallback".} - -## * \name Log File Configuration -## * The properties for configuring logging to files. -## @warning `usePlaintext` results in significantly larger log files and higher CPU usage that may slow -## down your app; we recommend turning it off in production. -type - CBLLogFileConfiguration* {.bycopy.} = object - directory*: cstring ## /< The directory where log files will be created. - maxRotateCount*: uint32 ## /< Max number of older logs to keep (i.e. total number will be one more.) - maxSize*: csize_t ## /< The size in bytes at which a file will be rotated out (best effort). - usePlaintext*: bool ## /< Whether or not to log in plaintext (as opposed to binary) - - -## * Gets the current file logging configuration. -proc fileConfig*(): ptr CBLLogFileConfiguration {.importc: "CBLLog_FileConfig".} - -## * Sets the file logging configuration. -proc setFileConfig*(a1: CBLLogFileConfiguration) {. - importc: "CBLLog_SetFileConfig".} - - - - -## -## CBLDatabase.h -## -## Copyright (c) 2018 Couchbase, Inc All rights reserved. -## -## 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. -## -## \defgroup database CBLDatabase -## A \ref CBLDatabase is both a filesystem object and a container for documents. - -## \name CBLDatabase configuration -## Flags for how to open a database. -type - CBLDatabaseFlags* {.size: sizeof(cint).} = enum - kDatabaseCreate = 1, ## Create the file if it doesn't exist - kDatabaseReadOnly = 2, ## Open file read-only - kDatabaseNoUpgrade = 4 ## Disable upgrading an older-version database - - -## Encryption algorithms (available only in the Enterprise Edition). -type - CBLEncryptionAlgorithm* {.size: sizeof(cint).} = enum - kEncryptionNone = 0, ## No encryption (default) - ## #ifdef COUCHBASE_ENTERPRISE - kEncryptionAES256 ## AES with 256-bit key - ## #endif - - -## Encryption key sizes (in bytes). -type - CBLEncryptionKeySize* {.size: sizeof(cint).} = enum - kEncryptionKeySizeAES256 = 32 ## Key size for \ref kCBLEncryptionAES256 - - -## Encryption key specified in a \ref CBLDatabaseConfiguration. -type - CBLEncryptionKey* {.bycopy.} = object - algorithm*: CBLEncryptionAlgorithm ## Encryption algorithm - bytes*: array[32, uint8] ## Raw key data - - -## CBLDatabase configuration options. -type - CBLDatabaseConfiguration* = object - directory*: cstring ## The parent directory of the database - flags*: CBLDatabaseFlags ## Options for opening the database - encryptionKey*: ptr CBLEncryptionKey ## The database's encryption key (if any) - - -## \name CBLDatabase file operations -## These functions operate on database files without opening them. -## -## Returns true if a database with the given name exists in the given directory. -## absolute or relative path to the database. -proc databaseExists*(name: cstring; inDirectory: cstring): bool {. - importc: "CBL_DatabaseExists".} - -## Copies a database file to a new location, and assigns it a new internal UUID to distinguish -## it from the original database when replicating. -proc copyDatabase*(fromPath: cstring; toName: cstring; - config: CBLDatabaseConfiguration; err: var CBLError): bool {. - importc: "CBL_CopyDatabase".} - -## Deletes a database file. If the database file is open, an error is returned. -## absolute or relative path to the database. -## (You can tell the last two cases apart by looking at \p outError.) -proc deleteDatabase*(name: cstring; inDirectory: cstring; - err: var CBLError): bool {.importc: "CBL_DeleteDatabase".} - -## \name CBLDatabase lifecycle -## Opening, closing, and managing open databases. -## -## Opens a database, or creates it if it doesn't exist yet, returning a new \ref CBLDatabase -## instance. -## It's OK to open the same database file multiple times. Each \ref CBLDatabase instance is -## independent of the others (and must be separately closed and released.) -proc openDatabase*(name: cstring; config: ptr CBLDatabaseConfiguration; - err: var CBLError): CBLDatabase {.importc: "CBLDatabase_Open".} - -## Closes an open database. -proc close*(a1: CBLDatabase; err: var CBLError): bool {. - importc: "CBLDatabase_Close".} - -## Closes and deletes a database. If there are any other connections to the database, -## an error is returned. -proc delete*(a1: CBLDatabase; err: var CBLError): bool {. - importc: "CBLDatabase_Delete".} - -## Compacts a database file. -proc compact*(a1: CBLDatabase; err: var CBLError): bool {. - importc: "CBLDatabase_Compact".} - -## Begins a batch operation, similar to a transaction. You **must** later call \ref -## CBLDatabase_EndBatch to end (commit) the batch. -## the batch operation ends. -proc beginBatch*(a1: CBLDatabase; err: var CBLError): bool {. - importc: "CBLDatabase_BeginBatch".} - -## Ends a batch operation. This **must** be called after \ref CBLDatabase_BeginBatch. -proc endBatch*(a1: CBLDatabase; err: var CBLError): bool {. - importc: "CBLDatabase_EndBatch".} - -## Returns the nearest future time at which a document in this database will expire, -## or 0 if no documents will expire. -proc nextDocExpiration*(a1: CBLDatabase): CBLTimestamp {. - importc: "CBLDatabase_NextDocExpiration".} - -## Purges all documents whose expiration time has passed. -proc purgeExpiredDocuments*(db: CBLDatabase; err: var CBLError): int64 {. - importc: "CBLDatabase_PurgeExpiredDocuments".} - -## \name CBLDatabase accessors -## Getting information about a database. -## -## Returns the database's name. -proc name*(a1: CBLDatabase): cstring {.importc: "CBLDatabase_Name".} - -## Returns the database's full filesystem path. -proc path*(a1: CBLDatabase): cstring {.importc: "CBLDatabase_Path".} - -## Returns the number of documents in the database. -proc count*(a1: CBLDatabase): uint64 {.importc: "CBLDatabase_Count".} - -## Returns the database's configuration, as given when it was opened. -proc config*(a1: CBLDatabase): CBLDatabaseConfiguration {. - importc: "CBLDatabase_Config".} - -## \name CBLDatabase listeners -## A database change listener lets you detect changes made to all documents in a database. -## (If you only want to observe specific documents, use a \ref CBLDocumentChangeListener instead.) -## listeners will be notified of changes made by other database instances. -## A database change listener callback, invoked after one or more documents are changed on disk. -## prepared for that, you may want to use \ref CBLDatabase_BufferNotifications -## so that listeners will be called in a safe context. -type - DatabaseChangeListener* = proc (context: pointer; db: CBLDatabase; - numDocs: cuint; docIDs: cstringArray) - -## Registers a database change listener callback. It will be called after one or more -## documents are changed on disk. -## listener. -proc addChangeListener*(db: CBLDatabase; listener: DatabaseChangeListener; - context: pointer): CBLListenerToken {. - importc: "CBLDatabase_AddChangeListener".} - -## end of outer \defgroup -## \defgroup listeners Listeners -## \name Scheduling notifications -## Applications may want control over when Couchbase Lite notifications (listener callbacks) -## happen. They may want them called on a specific thread, or at certain times during an event -## loop. This behavior may vary by database, if for instance each database is associated with a -## separate thread. -## -## The API calls here enable this. When notifications are "buffered" for a database, calls to -## listeners will be deferred until the application explicitly allows them. Instead, a single -## callback will be issued when the first notification becomes available; this gives the app a -## chance to schedule a time when the notifications should be sent and callbacks called. -## -## Callback indicating that the database (or an object belonging to it) is ready to call one -## or more listeners. You should call \ref CBLDatabase_SendNotifications at your earliest -## convenience, in the context (thread, dispatch queue, etc.) you want them to run. -## is called. If you don't respond by (sooner or later) calling that function, -## you will not be informed that any listeners are ready. -## possible, just scheduling a future call to \ref CBLDatabase_SendNotifications. -type - NotificationsReadyCallback* = proc (context: pointer; db: CBLDatabase) - -## Switches the database to buffered-notification mode. Notifications for objects belonging -## to this database (documents, queries, replicators, and of course the database) will not be -## called immediately; your \ref CBLNotificationsReadyCallback will be called instead. -proc bufferNotifications*(db: CBLDatabase; callback: NotificationsReadyCallback; - context: pointer) {.importc: "CBLDatabase_BufferNotifications".} - -## Immediately issues all pending notifications for this database, by calling their listener -## callbacks. -proc sendNotifications*(db: CBLDatabase) {. - importc: "CBLDatabase_SendNotifications".} - - - - -## CBLDocument.h -## -## Copyright (c) 2018 Couchbase, Inc All rights reserved. -## -## 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. -## -## \defgroup documents Documents -## A \ref CBLDocument is essentially a JSON object with an ID string that's unique in its database. -## -## \name CBLDocument lifecycle -## Conflict-handling options when saving or deleting a document. -type - CBLConcurrencyControl* {.size: sizeof( - cint).} = enum ## The current save/delete will overwrite a conflicting revision if there is a conflict. - kConcurrencyControlLastWriteWins, ## The current save/delete will fail if there is a conflict. - kConcurrencyControlFailOnConflict - - -## Custom conflict handler for use when saving or deleting a document. This handler is called -## if the save would cause a conflict, i.e. if the document in the database has been updated -## (probably by a pull replicator, or by application code on another thread) -## since it was loaded into the CBLDocument being saved. -type - CBLSaveConflictHandler* = proc (context: pointer; - documentBeingSaved: CBLDocument; conflictingDocument: CBLDocument): bool - -## Reads a document from the database, creating a new (immutable) \ref CBLDocument object. -## Each call to this function creates a new object (which must later be released.) -## \ref CBLDatabase_GetMutableDocument instead. -proc getDocument*(database: CBLDatabase; docID: cstring): CBLDocument {. - importc: "CBLDatabase_GetDocument".} - -## Saves a (mutable) document to the database. -## If a conflicting revision has been saved since \p doc was loaded, the \p concurrency -## parameter specifies whether the save should fail, or the conflicting revision should -## be overwritten with the revision being saved. -## If you need finer-grained control, call \ref CBLDatabase_SaveDocumentResolving instead. -proc saveDocument*(db: CBLDatabase; doc: CBLDocument; - concurrency: CBLConcurrencyControl; err: var CBLError): CBLDocument {. - importc: "CBLDatabase_SaveDocument".} - -## Saves a (mutable) document to the database. This function is the same as \ref -## CBLDatabase_SaveDocument, except that it allows for custom conflict handling in the event -## that the document has been updated since \p doc was loaded. -proc saveDocumentResolving*(db: CBLDatabase; doc: CBLDocument; - conflictHandler: CBLSaveConflictHandler; context: pointer; - err: var CBLError): CBLDocument {. - importc: "CBLDatabase_SaveDocumentResolving".} - -## Deletes a document from the database. Deletions are replicated. -proc delete*(document: CBLDocument; concurrency: CBLConcurrencyControl; - err: var CBLError): bool {.importc: "CBLDocument_Delete".} - -## Purges a document. This removes all traces of the document from the database. -## Purges are _not_ replicated. If the document is changed on a server, it will be re-created -## when pulled. -## simpler shortcut. -proc purge*(document: CBLDocument; err: var CBLError): bool {. - importc: "CBLDocument_Purge".} - -## Purges a document, given only its ID. -## code will be zero. -## -proc purgeDocumentByID*(database: CBLDatabase; docID: cstring; - err: var CBLError): bool {.importc: "CBLDatabase_PurgeDocumentByID".} - -## \name Mutable documents -## The type `CBLDocument*` without a `const` qualifier refers to a _mutable_ document instance. -## A mutable document exposes its properties as a mutable dictionary, so you can change them -## in place and then call \ref CBLDatabase_SaveDocument to persist the changes. -## -## Reads a document from the database, in mutable form that can be updated and saved. -## (This function is otherwise identical to \ref CBLDatabase_GetDocument.) -proc getMutableDocument*(database: CBLDatabase; docID: cstring): CBLDocument {. - importc: "CBLDatabase_GetMutableDocument".} - -## Creates a new, empty document in memory. It will not be added to a database until saved. -proc newDocument*(docID: cstring): CBLDocument {.importc: "CBLDocument_New".} - -## Creates a new mutable CBLDocument instance that refers to the same document as the original. -## If the original document has unsaved changes, the new one will also start out with the same -## changes; but mutating one document thereafter will not affect the other. -proc mutableCopy*(original: CBLDocument): CBLDocument {. - importc: "CBLDocument_MutableCopy".} - -## \name CBLDocument properties and metadata -## A document's body is essentially a JSON object. The properties are accessed in memory -## using the Fleece API, with the body itself being a \ref FLDict "dictionary"). -## -## Returns a document's ID. -proc id*(doc: CBLDocument): cstring {.importc: "CBLDocument_ID".} - -## Returns a document's revision ID, which is a short opaque string that's guaranteed to be -## unique to every change made to the document. -## If the document doesn't exist yet, this function returns NULL. -proc revisionID*(doc: CBLDocument): cstring {. - importc: "CBLDocument_RevisionID".} - -## Returns a document's current sequence in the local database. -## This number increases every time the document is saved, and a more recently saved document -## will have a greater sequence number than one saved earlier, so sequences may be used as an -## abstract 'clock' to tell relative modification times. -proc sequence*(doc: CBLDocument): uint64 {.importc: "CBLDocument_Sequence".} - -## Returns a document's properties as a dictionary. -## If you need to use any properties after releasing the document, you must retain them -## by calling \ref FLValue_Retain (and of course later release them.) -## underlying dictionary itself is mutable and could be modified through a mutable -## reference obtained via \ref CBLDocument_MutableProperties. If you need to preserve the -## properties, call \ref FLDict_MutableCopy to make a deep copy. -proc properties*(doc: CBLDocument): FLDict {.importc: "CBLDocument_Properties".} - -## Returns a mutable document's properties as a mutable dictionary. -## You may modify this dictionary and then call \ref CBLDatabase_SaveDocument to persist the changes. -## same collection returned by \ref CBLDocument_Properties. -## If you need to use any properties after releasing the document, you must retain them -## by calling \ref FLValue_Retain (and of course later release them.) -proc mutableProperties*(doc: CBLDocument): FLMutableDict {. - importc: "CBLDocument_MutableProperties".} - -## Sets a mutable document's properties. -## Call \ref CBLDatabase_SaveDocument to persist the changes. -## releasing any retained reference(s) you have to it. -proc setProperties*(doc: CBLDocument; properties: FLMutableDict) {. - importc: "CBLDocument_SetProperties".} - -proc createDocumentFleeceDoc*(doc: CBLDocument): FLDoc {. - importc: "CBLDocument_CreateFleeceDoc".} - -## Returns a document's properties as a null-terminated JSON string. -proc propertiesAsJSON*(doc: CBLDocument): cstring {. - importc: "CBLDocument_PropertiesAsJSON".} - -## Sets a mutable document's properties from a JSON string. -proc setPropertiesAsJSON*(doc: CBLDocument; json: cstring; - err: var CBLError): bool {.importc: "CBLDocument_SetPropertiesAsJSON".} - -## Returns the time, if any, at which a given document will expire and be purged. -## Documents don't normally expire; you have to call \ref CBLDatabase_SetDocumentExpiration -## to set a document's expiration time. -## or 0 if the document does not have an expiration, -## or -1 if the call failed. -proc getDocumentExpiration*(db: CBLDatabase; docID: cstring; - err: var CBLError): CBLTimestamp {. - importc: "CBLDatabase_GetDocumentExpiration".} - -## Sets or clears the expiration time of a document. -## \ref CBLDatabase_PurgeExpiredDocuments when the time comes, to make it happen. -## or 0 if the document should never expire. -proc setDocumentExpiration*(db: CBLDatabase; docID: cstring; - expiration: CBLTimestamp; err: var CBLError): bool {. - importc: "CBLDatabase_SetDocumentExpiration".} - -## \name CBLDocument listeners -## A document change listener lets you detect changes made to a specific document after they -## are persisted to the database. -## document listeners will be notified of changes made by other database instances. -## -## A document change listener callback, invoked after a specific document is changed on disk. -## prepared for that, you may want to use \ref CBLDatabase_BufferNotifications -## so that listeners will be called in a safe context. -type - DocumentChangeListener* = proc (context: pointer; db: CBLDatabase; - docID: cstring) - -## Registers a document change listener callback. It will be called after a specific document -## is changed on disk. -## listener. -proc addDocumentChangeListener*(db: CBLDatabase; docID: cstring; - listener: DocumentChangeListener; context: pointer): CBLListenerToken {. - importc: "CBLDatabase_AddDocumentChangeListener".} - - - - -## -## CBLBlob.h -## -## Copyright (c) 2018 Couchbase, Inc All rights reserved. -## -## 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. -## -## \defgroup blobs Blobs -## A \ref CBLBlob is a binary data blob associated with a document. -## -## The content of the blob is not stored in the document, but externally in the database. -## It is loaded only on demand, and can be streamed. Blobs can be arbitrarily large, although -## Sync Gateway will only accept blobs under 20MB. -## -## The document contains only a blob reference: a dictionary with the special marker property -## blob's data. This digest is used as the key to retrieve the blob data. -## The dictionary usually also has the property `length`, containing the blob's length in bytes, -## and it may have the property `content_type`, containing a MIME type. -## -## A \ref CBLBlob object acts as a proxy for such a dictionary in a \ref CBLDocument. Once -## you've loaded a document and located the \ref FLDict holding the blob reference, call -## \ref CBLBlob_Get on it to create a \ref CBLBlob object you can call. -## The object has accessors for the blob's metadata and for loading the data itself. -## -## To create a new blob from in-memory data, call \ref CBLBlob_CreateWithData, then call -## \ref FLMutableDict_SetBlob or \ref FLMutableArray_SetBlob to add the \ref CBLBlob to the -## document (or to a dictionary or array property of the document.) -## -## To create a new blob from a stream, call \ref CBLBlobWriter_New to create a -## \ref CBLBlobWriteStream, then make one or more calls to \ref CBLBlobWriter_Write to write -## data to the blob, then finally call \ref CBLBlob_CreateWithStream to create the blob. -## To store the blob into a document, do as in the previous paragraph. -## -## -var kTypeProperty* {.importc: "kCBLTypeProperty".}: FLSlice - - -var kBlobType* {.importc: "kCBLBlobType".}: FLSlice - -## `"blob"` -var kBlobDigestProperty* {.importc: "kCBLBlobDigestProperty".}: FLSlice - -## `"digest"` -var kBlobLengthProperty* {.importc: "kCBLBlobLengthProperty".}: FLSlice - -## `"length"` -var kBlobContentTypeProperty* {.importc: "kCBLBlobContentTypeProperty".}: FLSlice - -## `"content_type"` -## Returns true if a dictionary in a document is a blob reference. -## If so, you can call \ref CBLBlob_Get to access it. -## whose value is `"blob"`. -proc isBlob*(a1: FLDict): bool {.importc: "CBL_IsBlob".} - -## Returns a CBLBlob object corresponding to a blob dictionary in a document. -proc getBlob*(blobDict: FLDict): CBLBlob {.importc: "CBLBlob_Get".} - -## Returns the length in bytes of a blob's content (from its `length` property). -proc length*(a1: CBLBlob): uint64 {.importc: "CBLBlob_Length".} - -## Returns the cryptographic digest of a blob's content (from its `digest` property). -proc digest*(a1: CBLBlob): cstring {.importc: "CBLBlob_Digest".} - -## Returns a blob's MIME type, if its metadata has a `content_type` property. -proc contentType*(a1: CBLBlob): cstring {.importc: "CBLBlob_ContentType".} - -## Returns a blob's metadata. This includes the `digest`, `length` and `content_type` -## properties, as well as any custom ones that may have been added. -proc properties*(a1: CBLBlob): FLDict {.importc: "CBLBlob_Properties".} - -## Reads the blob's contents into memory and returns them. -## You are responsible for calling \ref FLFLSliceResult_Release on the returned data when done. -proc loadContent*(a1: CBLBlob; err: var CBLError): FLSliceResult {. - importc: "CBLBlob_LoadContent".} - -## A stream for reading a blob's content. -type - BlobReadStream* = ptr object - -## Opens a stream for reading a blob's content. -proc openContentStream*(a1: CBLBlob; err: var CBLError): ptr BlobReadStream {. - importc: "CBLBlob_OpenContentStream".} - -## Reads data from a blob. -proc read*(stream: ptr BlobReadStream; dst: pointer; maxLength: csize_t; - err: var CBLError): cint {.importc: "CBLBlobReader_Read".} - -## Closes a CBLBlobReadStream. -proc close*(a1: ptr BlobReadStream) {.importc: "CBLBlobReader_Close".} - -## Creates a new blob given its contents as a single block of data. -## has been saved. -proc createBlobWithData*(contentType: cstring; contents: FLSlice): CBLBlob {. - importc: "CBLBlob_CreateWithData".} - -## A stream for writing a new blob to the database. -type - BlobWriteStream* = ptr object - -## Opens a stream for writing a new blob. -## You should next call \ref CBLBlobWriter_Write one or more times to write the data, -## then \ref CBLBlob_CreateWithStream to create the blob. -## -## If for some reason you need to abort, just call \ref CBLBlobWriter_Close. -proc newBlobWriter*(db: CBLDatabase; err: var CBLError): ptr BlobWriteStream {. - importc: "CBLBlobWriter_New".} - -## Closes a blob-writing stream, if you need to give up without creating a \ref CBLBlob. -proc close*(a1: ptr BlobWriteStream) {.importc: "CBLBlobWriter_Close".} - -## Writes data to a new blob. -proc write*(writer: ptr BlobWriteStream; data: pointer; length: csize_t; - err: var CBLError): bool {.importc: "CBLBlobWriter_Write".} - -## Creates a new blob after its data has been written to a \ref CBLBlobWriteStream. -## You should then add the blob to a mutable document as a property -- see -## \ref FLMutableDict_SetBlob and \ref FLMutableArray_SetBlob. -proc createBlobWithStream*(contentType: cstring; - writer: ptr BlobWriteStream): CBLBlob {. - importc: "CBLBlob_CreateWithStream".} -proc createBlobWithStream_s*(contentType: cstring; - writer: ptr BlobWriteStream): CBLBlob {. - importc: "CBLBlob_CreateWithStream".} - -## Returns true if a value in a document is a blob reference. -## If so, you can call \ref FLValue_GetBlob to access it. -proc isBlob*(v: FLValue): bool {.inline.} = - return isBlob(asDict(v)) - -## Instantiates a \ref CBLBlob object corresponding to a blob dictionary in a document. -proc getBlob*(value: FLValue): CBLBlob {.inline.} = - return getBlob(asDict(value)) - -## Stores a blob in a mutable array or dictionary. -proc setBlob*(slot: FLSlot; blob: CBLBlob) {.importc: "FLSlot_SetBlob".} - - - - -## -## CBLQuery.h -## -## Copyright (c) 2018 Couchbase, Inc All rights reserved. -## -## 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. -## -## \defgroup queries Queries -## A CBLQuery represents a compiled database query. The query language is a large subset of -## the [N1QL](https://www.couchbase.com/products/n1ql) language from Couchbase Server, which -## you can think of as "SQL for JSON" or "SQL++". -## -## Queries may be given either in -## [N1QL syntax](https://docs.couchbase.com/server/6.0/n1ql/n1ql-language-reference/index.html), -## or in JSON using a -## [schema](https://github.com/couchbase/couchbase-lite-core/wiki/JSON-CBLQuery-Schema) -## that resembles a parse tree of N1QL. The JSON syntax is harder for humans, but much more -## amenable to machine generation, if you need to create queries programmatically or translate -## them from some other form. -## -## CBLQuery languages -type - CBLQueryLanguage* {.size: sizeof(cint).} = enum - kJSONLanguage, ## [JSON query schema](https://github.com/couchbase/couchbase-lite-core/wiki/JSON-CBLQuery-Schema) - kN1QLLanguage ## [N1QL syntax](https://docs.couchbase.com/server/6.0/n1ql/n1ql-language-reference/index.html) - - -## \name CBLQuery objects -## Creates a new query by compiling the input string. -## This is fast, but not instantaneous. If you need to run the same query many times, keep the -## \ref CBLQuery around instead of compiling it each time. If you need to run related queries -## with only some values different, create one query with placeholder parameter(s), and substitute -## the desired value(s) with \ref CBLQuery_SetParameters each time you run the query. -## [JSON](https://github.com/couchbase/couchbase-lite-core/wiki/JSON-CBLQuery-Schema) or -## [N1QL](https://docs.couchbase.com/server/4.0/n1ql/n1ql-language-reference/index.html). -## input expression will be stored here (or -1 if not known/applicable.) -proc newQuery*(db: CBLDatabase; language: CBLQueryLanguage; - queryFLString: cstring; outErrorPos: ptr cint; - err: var CBLError): CBLQuery {.importc: "CBLQuery_New".} - -## Assigns values to the query's parameters. -## These values will be substited for those parameters whenever the query is executed, -## until they are next assigned. -## -## Parameters are specified in the query source as -## e.g. `$PARAM` (N1QL) or `["$PARAM"]` (JSON). In this example, the `parameters` dictionary -## to this call should have a key `PARAM` that maps to the value of the parameter. -## keys are the parameter names. (It's easiest to construct this by using the mutable -## API, i.e. calling \ref FLMutableDict_New and adding keys/values.) -proc setParameters*(query: CBLQuery; parameters: FLDict) {. - importc: "CBLQuery_SetParameters".} - -## Returns the query's current parameter bindings, if any. -proc parameters*(query: CBLQuery): FLDict {.importc: "CBLQuery_Parameters".} - -## Assigns values to the query's parameters, from JSON data. -## See \ref CBLQuery_SetParameters for details. -## keys are the parameter names. (You may use JSON5 syntax.) -proc setParametersAsJSON*(query: CBLQuery; json: cstring): bool {. - importc: "CBLQuery_SetParametersAsJSON".} - -## Runs the query, returning the results. -## To obtain the results you'll typically call \ref CBLResultSet_Next in a `while` loop, -## examining the values in the \ref CBLResultSet each time around. -proc execute*(a1: CBLQuery; err: var CBLError): CBLResultSet {. - importc: "CBLQuery_Execute".} - -## Returns information about the query, including the translated SQLite form, and the search -## strategy. You can use this to help optimize the query: the word `SCAN` in the strategy -## indicates a linear scan of the entire database, which should be avoided by adding an index. -## The strategy will also show which index(es), if any, are used. -proc explain*(a1: CBLQuery): FLSliceResult {.importc: "CBLQuery_Explain".} - -## Returns the number of columns in each result. -proc columnCount*(a1: CBLQuery): cuint {.importc: "CBLQuery_ColumnCount".} - -## Returns the name of a column in the result. -## The column name is based on its expression in the `SELECT...` or `WHAT:` section of the -## query. A column that returns a property or property path will be named after that property. -## A column that returns an expression will have an automatically-generated name like `$1`. -## To give a column a custom name, use the `AS` syntax in the query. -## Every column is guaranteed to have a unique name. -proc columnName*(a1: CBLQuery; columnIndex: cuint): FLSlice {. - importc: "CBLQuery_ColumnName".} - -## \name Result sets -## A `CBLResultSet` is an iterator over the results returned by a query. It exposes one -## result at a time -- as a collection of values indexed either by position or by name -- -## and can be stepped from one result to the next. -## -## It's important to note that the initial position of the iterator is _before_ the first -## result, so \ref CBLResultSet_Next must be called _first_. Example: -## -## ``` -## CBLResultSet *rs = CBLQuery_Execute(query, &error); -## assert(rs); -## while (CBLResultSet_Next(rs) { -## FLValue aValue = CBLResultSet_ValueAtIndex(rs, 0); -## ... -## } -## CBLResultSet_Release(rs); -## ``` -## -## Moves the result-set iterator to the next result. -## Returns false if there are no more results. -proc next*(a1: CBLResultSet): bool {.importc: "CBLResultSet_Next".} - -## Returns the value of a column of the current result, given its (zero-based) numeric index. -## This may return a NULL pointer, indicating `MISSING`, if the value doesn't exist, e.g. if -## the column is a property that doesn't exist in the document. -proc valueAtIndex*(a1: CBLResultSet; index: cuint): FLValue {. - importc: "CBLResultSet_ValueAtIndex".} - -## Returns the value of a column of the current result, given its name. -## This may return a NULL pointer, indicating `MISSING`, if the value doesn't exist, e.g. if -## the column is a property that doesn't exist in the document. (Or, of course, if the key -## is not a column name in this query.) -proc valueForKey*(a1: CBLResultSet; key: cstring): FLValue {. - importc: "CBLResultSet_ValueForKey".} - -## Returns the current result as an array of column values. -## @warning The array reference is only valid until the result-set is advanced or released. -## If you want to keep it for longer, call \ref FLArray_Retain (and release it when done.) -proc rowArray*(rs: CBLResultSet): FLArray {.importc: "CBLResultSet_RowArray".} - -## Returns the current result as a dictionary mapping column names to values. -## @warning The dict reference is only valid until the result-set is advanced or released. -## If you want to keep it for longer, call \ref FLDict_Retain (and release it when done.) -proc rowDict*(rs: CBLResultSet): FLDict {.importc: "CBLResultSet_RowDict".} - -## Returns the CBLQuery that created this CBLResultSet. -proc getQuery*(rs: CBLResultSet): CBLQuery {.importc: "CBLResultSet_GetQuery".} - -## \name Change listener -## Adding a change listener to a query turns it into a "live query". When changes are made to -## documents, the query will periodically re-run and compare its results with the prior -## results; if the new results are different, the listener callback will be called. -## -## rows that changed. -## -## A callback to be invoked after the query's results have changed. -## The actual result set can be obtained by calling \ref CBLQuery_CurrentResults, either during -## the callback or at any time thereafter. -## prepared for that, you may want to use \ref CBLDatabase_BufferNotifications -## so that listeners will be called in a safe context. -type - CBLQueryChangeListner* = proc (context: pointer; query: CBLQuery) - -## Registers a change listener callback with a query, turning it into a "live query" until -## the listener is removed (via \ref CBLListener_Remove). -## -## When the first change listener is added, the query will run (in the background) and notify -## the listener(s) of the results when ready. After that, it will run in the background after -## the database changes, and only notify the listeners when the result set changes. -## listener. -proc addChangeListener*(query: CBLQuery; listener: CBLQueryChangeListner; - context: pointer): CBLListenerToken {. - importc: "CBLQuery_AddChangeListener".} - -## Returns the query's _entire_ current result set, after it's been announced via a call to the -## listener's callback. -proc copyCurrentResults*(query: CBLQuery; listener: CBLListenerToken; - err: var CBLError): CBLResultSet {.importc: "CBLQuery_CopyCurrentResults".} - -## \name CBLDatabase Indexes -## Indexes are used to speed up queries by allowing fast -- O(log n) -- lookup of documents -## that have specific values or ranges of values. The values may be properties, or expressions -## based on properties. -## -## An index will speed up queries that use the expression it indexes, but it takes up space in -## the database file, and it slows down document saves slightly because it needs to be kept up -## to date when documents change. -## -## Tuning a database with indexes can be a tricky task. Fortunately, a lot has been written about -## it in the relational-database (SQL) realm, and much of that advice holds for Couchbase Lite. -## You may find SQLite's documentation particularly helpful since Couchbase Lite's querying is -## based on SQLite. -## -## Two types of indexes are currently supported: -## FLValue indexes speed up queries by making it possible to look up property (or expression) -## values without scanning every document. They're just like regular indexes in SQL or N1QL. -## Multiple expressions are supported; the first is the primary key, second is secondary. -## Expressions must evaluate to scalar types (boolean, number, string). -## Full-Text Search (FTS) indexes enable fast search of natural-language words or phrases -## by using the `MATCH` operator in a query. A FTS index is **required** for full-text -## search: a query with a `MATCH` operator will fail to compile unless there is already a -## FTS index for the property/expression being matched. Only a single expression is -## currently allowed, and it must evaluate to a string. -## Types of database indexes. -type - CBLIndexType* {.size: sizeof(cint).} = enum - kValueIndex, ## An index that stores property or expression values - kFullTextIndex ## An index of strings, that enables searching for words with `MATCH` - - -## Parameters for creating a database index. -type - CBLIndexSpec* {.bycopy.} = object - `type`*: CBLIndexType ## The type of index to create. - ## A JSON array describing each column of the index. - keyExpressionsJSON*: cstring ## In a full-text index, should diacritical marks (accents) be ignored? - ## Defaults to false. Generally this should be left `false` for non-English text. - ignoreAccents*: bool ## In a full-text index, the dominant language. Setting this enables word stemming, i.e. - ## matching different cases of the same word ("big" and "bigger", for instance) and ignoring - ## common "stop-words" ("the", "a", "of", etc.) - ## - ## Can be an ISO-639 language code or a lowercase (English) language name; supported - ## languages are: da/danish, nl/dutch, en/english, fi/finnish, fr/french, de/german, - ## hu/hungarian, it/italian, no/norwegian, pt/portuguese, ro/romanian, ru/russian, - ## es/spanish, sv/swedish, tr/turkish. - ## - ## If left null, or set to an unrecognized language, no language-specific behaviors - ## such as stemming and stop-word removal occur. - language*: cstring - - -## Creates a database index. -## Indexes are persistent. -## If an identical index with that name already exists, nothing happens (and no error is returned.) -## If a non-identical index with that name already exists, it is deleted and re-created. -proc createDatabaseIndex*(db: CBLDatabase; name: cstring; a3: CBLIndexSpec; - err: var CBLError): bool {.importc: "CBLDatabase_CreateIndex".} - -## Deletes an index given its name. -proc deleteIndex*(db: CBLDatabase; name: cstring; err: var CBLError): bool {. - importc: "CBLDatabase_DeleteIndex".} - -## Returns the names of the indexes on this database, as an array of strings. -proc indexNames*(db: CBLDatabase): FLMutableArray {. - importc: "CBLDatabase_IndexNames".} - - - - -## -## CBLReplicator.h -## -## Copyright (c) 2018 Couchbase, Inc All rights reserved. -## -## 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. -## -## \defgroup replication Replication -## A replicator is a background task that synchronizes changes between a local database and -## another database on a remote server (or on a peer device, or even another local database.) -## \name Configuration -## The name of the HTTP cookie used by Sync Gateway to store session keys. -var kAuthDefaultCookieName* {.importc: "kCBLAuthDefaultCookieName".}: cstring - -type - CBLEndpoint* = ptr object - CBLAuthenticator* = ptr object ## An opaque object representing authentication credentials for a remote server. - -## Creates a new endpoint representing a server-based database at the given URL. -## The URL's scheme must be `ws` or `wss`, it must of course have a valid hostname, -## and its path must be the name of the database on that server. -## The port can be omitted; it defaults to 80 for `ws` and 443 for `wss`. -## For example: `wss://example.org/dbname` -proc newEndpointWithURL*(url: cstring): CBLEndpoint {. - importc: "CBLEndpoint_NewWithURL".} - -## Creates a new endpoint representing another local database. (Enterprise Edition only.) -proc newEndpointWithLocalDB*(db: CBLDatabase): CBLEndpoint {. - importc: "CBLEndpoint_NewWithLocalDB".} - -## Frees a CBLEndpoint object. -proc free*(a1: CBLEndpoint) {.importc: "CBLEndpoint_Free".} - - -## Creates an authenticator for HTTP Basic (username/password) auth. -proc newAuthBasic*(username: cstring; password: cstring): CBLAuthenticator {. - importc: "CBLAuth_NewBasic".} - -## Creates an authenticator using a Couchbase Sync Gateway login session identifier, -## and optionally a cookie name (pass NULL for the default.) -proc newAuthSession*(sessionID: cstring; - cookieName: cstring): CBLAuthenticator {.importc: "CBLAuth_NewSession".} - -## Frees a CBLAuthenticator object. -proc free*(a1: CBLAuthenticator) {.importc: "CBLAuth_Free".} - -## Direction of replication: push, pull, or both. -type - CBLReplicatorType* {.size: sizeof(cint).} = enum - kReplicatorTypePushAndPull = 0, ## Bidirectional; both push and pull - kReplicatorTypePush, ## Pushing changes to the target - kReplicatorTypePull ## Pulling changes from the target - - -## A callback that can decide whether a particular document should be pushed or pulled. -## It must pay attention to thread-safety. It should not take a long time to return, -## or it will slow down the replicator. -type - CBLReplicationFilter* = proc (context: pointer; document: CBLDocument; - isDeleted: bool): bool - -## Conflict-resolution callback for use in replications. This callback will be invoked -## when the replicator finds a newer server-side revision of a document that also has local -## changes. The local and remote changes must be resolved before the document can be pushed -## to the server. -## It must pay attention to thread-safety. However, unlike a filter callback, -## it does not need to return quickly. If it needs to prompt for user input, -## that's OK. -## or NULL if the local document has been deleted. -## or NULL if the document has been deleted on the server. -## This can be the same as \p localDocument or \p remoteDocument, or you can create -## a mutable copy of either one and modify it appropriately. -## Or return NULL if the resolution is to delete the document. -type - CBLConflictResolver* = proc (context: pointer; documentID: cstring; - localDocument: CBLDocument; remoteDocument: CBLDocument): CBLDocument - -## Default conflict resolver. This always returns `localDocument`. -var defaultConflictResolver* {.importc: "CBLDefaultConflictResolver".}: CBLConflictResolver - -## Types of proxy servers, for CBLProxySettings. -type - CBLProxyType* {.size: sizeof(cint).} = enum - kProxyHTTP, ## HTTP proxy; must support 'CONNECT' method - kProxyHTTPS ## HTTPS proxy; must support 'CONNECT' method - - -## Proxy settings for the replicator. -type - CBLProxySettings* {.bycopy.} = object - `type`*: CBLProxyType ## Type of proxy - hostname*: cstring ## Proxy server hostname or IP address - port*: uint16 ## Proxy server port - username*: cstring ## Username for proxy auth (optional) - password*: cstring ## Password for proxy auth - - -## The configuration of a replicator. -type - CBLReplicatorConfiguration* {.bycopy.} = object - database*: CBLDatabase ## The database to replicate - endpoint*: CBLEndpoint ## The address of the other database to replicate with - replicatorType*: CBLReplicatorType ## Push, pull or both - continuous*: bool ## Continuous replication? - ## -- HTTP settings: - authenticator*: CBLAuthenticator ## Authentication credentials, if needed - proxy*: ptr CBLProxySettings ## HTTP client proxy settings - headers*: FLDict ## Extra HTTP headers to add to the WebSocket request - ## -- TLS settings: - pinnedServerCertificate*: FLSlice ## An X.509 cert to "pin" TLS connections to (PEM or DER) - trustedRootCertificates*: FLSlice ## Set of anchor certs (PEM format) - ## -- Filtering: - channels*: FLArray ## Optional set of channels to pull from - documentIDs*: FLArray ## Optional set of document IDs to replicate - pushFilter*: CBLReplicationFilter ## Optional callback to filter which docs are pushed - pullFilter*: CBLReplicationFilter ## Optional callback to validate incoming docs - conflictResolver*: CBLConflictResolver ## Optional conflict-resolver callback - context*: pointer ## Arbitrary value that will be passed to callbacks - - -## \name Lifecycle -## Creates a replicator with the given configuration. -proc newReplicator*(a1: ptr CBLReplicatorConfiguration; - err: var CBLError): CBLReplicator {.importc: "CBLReplicator_New".} - -## Returns the configuration of an existing replicator. -proc config*(a1: CBLReplicator): ptr CBLReplicatorConfiguration {. - importc: "CBLReplicator_Config".} - -## Instructs the replicator to ignore existing checkpoints the next time it runs. -## This will cause it to scan through all the documents on the remote database, which takes -## a lot longer, but it can resolve problems with missing documents if the client and -## server have gotten out of sync somehow. -proc resetCheckpoint*(a1: CBLReplicator) {. - importc: "CBLReplicator_ResetCheckpoint".} - -## Starts a replicator, asynchronously. Does nothing if it's already started. -proc start*(a1: CBLReplicator) {.importc: "CBLReplicator_Start".} - -## Stops a running replicator, asynchronously. Does nothing if it's not already started. -## The replicator will call your \ref CBLReplicatorChangeListener with an activity level of -## \ref kCBLReplicatorStopped after it stops. Until then, consider it still active. -proc stop*(a1: CBLReplicator) {.importc: "CBLReplicator_Stop".} - -## Informs the replicator whether it's considered possible to reach the remote host with -## the current network configuration. The default value is true. This only affects the -## replicator's behavior while it's in the Offline state: -## Setting it to false will cancel any pending retry and prevent future automatic retries. -## Setting it back to true will initiate an immediate retry. -proc setHostReachable*(a1: CBLReplicator; reachable: bool) {. - importc: "CBLReplicator_SetHostReachable".} - -## Puts the replicator in or out of "suspended" state. The default is false. -## Setting suspended=true causes the replicator to disconnect and enter Offline state; -## it will not attempt to reconnect while it's suspended. -## Setting suspended=false causes the replicator to attempt to reconnect, _if_ it was -## connected when suspended, and is still in Offline state. -proc setSuspended*(repl: CBLReplicator; suspended: bool) {. - importc: "CBLReplicator_SetSuspended".} - -## \name Status and Progress -## -## The possible states a replicator can be in during its lifecycle. -type - CBLReplicatorActivityLevel* {.size: sizeof(cint).} = enum - kReplicatorStopped, ## The replicator is unstarted, finished, or hit a fatal error. - kReplicatorOffline, ## The replicator is offline, as the remote host is unreachable. - kReplicatorConnecting, ## The replicator is connecting to the remote host. - kReplicatorIdle, ## The replicator is inactive, waiting for changes to sync. - kReplicatorBusy ## The replicator is actively transferring data. - - -## A fractional progress value, ranging from 0.0 to 1.0 as replication progresses. -## The value is very approximate and may bounce around during replication; making it more -## accurate would require slowing down the replicator and incurring more load on the server. -## It's fine to use in a progress bar, though. -type - CBLReplicatorProgress* {.bycopy.} = object - fractionComplete*: cfloat ## / Very-approximate completion, from 0.0 to 1.0 - documentCount*: uint64 ## Number of documents transferred so far - - -## A replicator's current status. -type - ReplicatorStatus* {.bycopy.} = object - activity*: CBLReplicatorActivityLevel ## Current state - progress*: CBLReplicatorProgress ## Approximate fraction complete - error*: CBLError ## CBLError, if any - - -## Returns the replicator's current status. -proc getStatus*(a1: CBLReplicator): ReplicatorStatus {. - importc: "CBLReplicator_GetStatus".} - -## Indicates which documents have local changes that have not yet been pushed to the server -## by this replicator. This is of course a snapshot, that will go out of date as the replicator -## makes progress and/or documents are saved locally. -## -## The result is, effectively, a set of document IDs: a dictionary whose keys are the IDs and -## values are `true`. -## If there are no pending documents, the dictionary is empty. -## On error, NULL is returned. -## -## \note This function can be called on a stopped or un-started replicator. -## \note Documents that would never be pushed by this replicator, due to its configuration's -## `pushFilter` or `docIDs`, are ignored. -## \warning You are responsible for releasing the returned array via \ref FLValue_Release. -proc pendingDocumentIDs*(a1: CBLReplicator; err: var CBLError): FLDict {. - importc: "CBLReplicator_PendingDocumentIDs".} - -## Indicates whether the document with the given ID has local changes that have not yet been -## pushed to the server by this replicator. -## -## This is equivalent to, but faster than, calling \ref CBLReplicator_PendingDocumentIDs and -## checking whether the result contains \p docID. See that function's documentation for details. -## -## \note A `false` result means the document is not pending, _or_ there was an error. -## To tell the difference, compare the error code to zero. -proc isDocumentPending*(repl: CBLReplicator; docID: FLString; - err: var CBLError): bool {.importc: "CBLReplicator_IsDocumentPending".} - -## A callback that notifies you when the replicator's status changes. -## It must pay attention to thread-safety. It should not take a long time to return, -## or it will slow down the replicator. -type - CBLReplicatorChangeListener* = proc (context: pointer; - replicator: CBLReplicator; status: ptr ReplicatorStatus) - -## Adds a listener that will be called when the replicator's status changes. -proc addChangeListener*(a1: CBLReplicator; a2: CBLReplicatorChangeListener; - context: pointer): CBLListenerToken {. - importc: "CBLReplicator_AddChangeListener".} - -## Flags describing a replicated document. -type - CBLDocumentFlags* {.size: sizeof(cint).} = enum - kDocumentFlagsDeleted = 1 shl 0, ## The document has been deleted. - kDocumentFlagsAccessRemoved = 1 shl 1 - - -## Information about a document that's been pushed or pulled. -type - CBLReplicatedDocument* {.bycopy.} = object - id*: cstring ## The document ID - flags*: CBLDocumentFlags ## Indicates whether the document was deleted or removed - error*: CBLError ## If the code is nonzero, the document failed to replicate. - - -## A callback that notifies you when documents are replicated. -## It must pay attention to thread-safety. It should not take a long time to return, -## or it will slow down the replicator. -type - CBLReplicatedDocumentListener* = proc (context: pointer; - replicator: CBLReplicator; isPush: bool; numDocuments: cuint; - documents: ptr CBLReplicatedDocument) - -## Adds a listener that will be called when documents are replicated. -proc addDocumentListener*(a1: CBLReplicator; a2: CBLReplicatedDocumentListener; - context: pointer): CBLListenerToken {. - importc: "CBLReplicator_AddDocumentListener".} - -{.pop.} diff --git a/bindings/nim/src/CouchbaseLite/private/fl.nim b/bindings/nim/src/CouchbaseLite/private/fl.nim deleted file mode 100644 index 58c2859a..00000000 --- a/bindings/nim/src/CouchbaseLite/private/fl.nim +++ /dev/null @@ -1,1004 +0,0 @@ -## *** NOTE: DO NOT MACHINE-UPDATE THIS FILE *** -## -## This started out as a machine-generated file (produced by `gen-bindings.sh`), -## but it has been hand-edited to fix issues that kept it from compiling. -## -## If you run the script again, it will generate a _new_ file `Fleece-new.nim`. -## You'll need to merge new/changed declarations from that file into this one, by hand. -## -## Status: Up-to-date as of 5 May 2020, commit 036cd9f7 "Export kCBLAuthDefaultCookieName...", -## Fleece commit 4ca3dbf1, "Mutable.hh: Allow conversion of keyRef and FLSlot to FLSlot". - - -when defined(Linux): - {.push dynlib: "libcblite.so".} -elif defined(MacOS) or defined(MacOSX): - {.push dynlib: "libcblite.dylib".} -elif defined(Windows): - {.push dynlib: "cblite.dll".} - - -## FLSlice.h -## Fleece -## -## Created by Jens Alfke on 8/13/18. -## Copyright © 2018 Couchbase. All rights reserved. -## -## A simple reference to a block of memory. Does not imply ownership. -## (This is equivalent to the C++ class `slice`.) -type - FLSlice* {.bycopy.} = object - buf*: pointer - size*: csize_t - - -## A block of memory returned from an API call. The caller takes ownership, and must call -## FLSlice_Release (or FLSlice_Free) when done. The heap block may be shared with other users, -## so it must not be modified. -## (This is equivalent to the C++ class `alloc_slice`.) -type - FLSliceResult* {.bycopy.} = object - buf*: pointer - size*: csize_t - - -## A heap-allocated, reference-counted slice. This type is really just a hint in an API -## that the data can be retained instead of copied, by assigning it to an alloc_slice. -## You can just treat it like FLSlice. -type - FLHeapSlice* = FLSlice - -type - FLString* = FLSlice - FLStringResult* = FLSliceResult - -## Slice <-> string conversion: -proc flStr*(str: string): FLSlice = - FLSlice(buf: cstring(str), size: csize_t(len(str))) - - -## Equality test of two slices. -proc equal*(a: FLSlice; b: FLSlice): bool {.importc: "FLSlice_Equal".} - -## Lexicographic comparison of two slices; basically like memcmp(), but taking into account -## differences in length. -proc compare*(a1: FLSlice; a2: FLSlice): cint {.importc: "FLSlice_Compare".} - -## Allocates an FLSliceResult of the given size, without initializing the buffer. -proc newSliceResult*(a1: csize_t): FLSliceResult {.importc: "FLSliceResult_New".} - -## Allocates an FLSliceResult, copying the given slice. -proc copy*(a1: FLSlice): FLSliceResult {.importc: "FLSlice_Copy".} - -proc internalFLBufRetain(a1: pointer) {.importc: "_FLBuf_Retain".} -proc internalFLBufRelease(a1: pointer) {.importc: "_FLBuf_Release".} - - -# Hand-written: Automatic ref-counting for FLSliceResult -# (see: ) - -proc `=destroy`(s: var FLSliceResult) = - internalFLBufRelease(s.buf) - -proc `=`(dest: var FLSliceResult; source: FLSliceResult) = - let oldBuf = dest.buf - if oldBuf != source.buf: - internalFLBufRetain(source.buf) - dest.buf = source.buf - internalFLBufRelease(oldBuf) - dest.size = source.size - - -#%%%%%%% NIM CONVERSIONS FOR SLICES: -proc asSlice*(s: FLSliceResult): fl.FLSlice = - FLSlice(buf: s.buf, size: s.size) - -proc asSlice*(bytes: openarray[byte]): fl.FLSlice = - FLSlice(buf: unsafeAddr bytes[0], size: csize_t(bytes.len)) - -proc asSlice*(str: string): fl.FLSlice = - FLSlice(buf: unsafeAddr str[0], size: csize_t(str.len)) - -proc toString*(s: FLSlice): string = - if s.buf == nil: return "" - var str = newString(s.size) - copyMem(addr str[0], s.buf, s.size) - return str - -proc toString*(s: FLSliceResult): string = - toString(s.asSlice()) - -proc toByteArray*(s: FLSlice): seq[uint8] = - var bytes = newSeq[uint8](s.size) - copyMem(addr bytes[0], s.buf, s.size) - return bytes - -## -## Fleece.h -## -## Copyright (c) 2016 Couchbase, Inc All rights reserved. -## -## 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. -## -## This is the C API! For the C++ API, see Fleece.hh. - -## ////// BASIC TYPES -type - FLValue* = ptr object ## A reference to a value of any type. - FLArray* = ptr object ## A reference to an array value. - FLDict* = ptr object ## A reference to a dictionary (map) value. - FLSlot* = ptr object ## A reference to a mutable array/dict item - FLMutableArray* = ptr object ## A reference to a mutable array. - FLMutableDict* = ptr object ## A reference to a mutable dictionary. - -## Error codes returned from some API calls. -type - FLError* {.size: sizeof(cint).} = enum - NoError = 0, - MemoryError, ## Out of memory, or allocation failed - OutOfRange, ## Array index or iterator out of range - InvalidData, ## Bad input data (NaN, non-string key, etc.) - EncodeError, ## Structural error encoding (missing value, too many ends, etc.) - JSONError, ## Error parsing JSON - UnknownValue, ## Unparseable data in a FLValue (corrupt? Or from some distant future?) - InternalError, ## Something that shouldn't happen - NotFound, ## Key not found - SharedKeysStateError, ## Misuse of shared keys (not in transaction, etc.) - POSIXError, ## POSIX API call failed - Unsupported ## Operation is unsupported - - - -## ////// DOCUMENT -## An FLDoc points to (and often owns) Fleece-encoded data and provides access to its -## Fleece values. -## -type - FLDoc* = ptr object ## A reference to a document. - SharedKeys* = ptr object ## A reference to a shared-keys mapping. - -## Specifies whether not input data is trusted to be 100% valid Fleece. -type ## Input data is not trusted to be valid, and will be fully validated by the API call. - FLTrust* {.size: sizeof(cint).} = enum - kUntrusted, ## Input data is trusted to be valid. The API will perform only minimal validation when - ## reading it. This is faster than kFLUntrusted, but should only be used if - ## the data was generated by a trusted encoder and has not been altered or corrupted. For - ## example, this can be used to parse Fleece data previously stored by your code in local - ## storage. - ## If invalid data is read by this call, subsequent calls to FLValue accessor functions can - ## crash or return bogus results (including data from arbitrary memory locations.) - kTrusted - - -## Creates an FLDoc from Fleece-encoded data that's been returned as a result from -## FLSlice_Copy or other API. The resulting document retains the data, so you don't need to -## worry about it remaining valid. -proc newDocFromResultData*(data: FLSliceResult; a2: FLTrust; a3: SharedKeys; externData: FLSlice): FLDoc {.importc: "FLDoc_FromResultData".} - -## Creates an FLDoc from JSON-encoded data. The data is first encoded into Fleece, and the -## Fleece data is kept by the doc; the input JSON data is no longer needed after this -## function returns. -proc newDocFromJSON*(json: FLSlice; outError: var FLError): FLDoc {.importc: "FLDoc_FromJSON".} - -## Releases a reference to an FLDoc. This must be called once to free an FLDoc you created. -proc release*(a1: FLDoc) {.importc: "FLDoc_Release".} - -## Adds a reference to an FLDoc. This extends its lifespan until at least such time as you -## call FLRelease to remove the reference. -proc retain*(a1: FLDoc): FLDoc {.importc: "FLDoc_Retain".} - -## Returns the encoded Fleece data backing the document. -proc getData*(a1: FLDoc): FLSlice {.importc: "FLDoc_GetData".} - -## Returns the FLSliceResult data owned by the document, if any, else a null slice. -proc getAllocedData*(a1: FLDoc): FLSliceResult {.importc: "FLDoc_GetAllocedData".} - -## Returns the root value in the FLDoc, usually an FLDict. -proc getRoot*(a1: FLDoc): FLValue {.importc: "FLDoc_GetRoot".} - -## Returns the FLSharedKeys used by this FLDoc, as specified when it was created. -proc getSharedKeys*(a1: FLDoc): SharedKeys {.importc: "FLDoc_GetSharedKeys".} - -## Looks up the FLDoc containing the FLValue, or NULL if the FLValue was created without a FLDoc. -## Caller must release the FLDoc reference!! -proc findDoc*(a1: FLValue): FLDoc {.importc: "FLValue_FindDoc".} - - - -## Returns a pointer to the root value in the encoded data, or NULL if validation failed. -## The FLValue, and all values found through it, are only valid as long as the encoded data -## remains intact and unchanged. -proc newValueFromData*(data: FLSlice; a2: FLTrust): FLValue {.importc: "FLValue_FromData".} - -## Directly converts JSON data to Fleece-encoded data. -## You can then call FLValue_FromData (in kFLTrusted mode) to get the root as a FLValue. -proc convertJSON*(json: FLSlice; outError: var FLError): FLSliceResult {.importc: "FLData_ConvertJSON".} - -## Produces a human-readable dump of the FLValue encoded in the data. -## This is only useful if you already know, or want to learn, the encoding format. -proc dump*(data: FLSlice): FLStringResult {.importc: "FLData_Dump".} - -## These are convenience functions that directly return JSON-encoded output. -## For more control over the encoding, use an FLEncoder. -## Encodes a Fleece value as JSON (or a JSON fragment.) -## Any Data values will become base64-encoded JSON strings. -proc toJSON*(a1: FLValue): FLStringResult {.importc: "FLValue_ToJSON".} - -## Encodes a Fleece value as JSON5, a more lenient variant of JSON that allows dictionary -## keys to be unquoted if they're alphanumeric. This tends to be more readable. -proc toJSON5*(v: FLValue): FLStringResult {.importc: "FLValue_ToJSON5".} - -## Most general Fleece to JSON converter. -proc toJSONX*(v: FLValue; json5: bool; canonicalForm: bool): FLStringResult {.importc: "FLValue_ToJSONX".} - -## Converts valid JSON5 to JSON. Among other things, it converts single -## quotes to double, adds missing quotes around dictionary keys, removes trailing commas, -## and removes comments. -## comparably invalid JSON, in which case the caller's subsequent JSON parsing will -## detect the error. The types of errors it overlooks tend to be subtleties of string -## or number encoding. -## As this is a \ref FLStringResult, you will be responsible for freeing it. -## will be stored here (if it's not NULL.) -proc jSON5ToJSON*(json5: FLString; outErrorMessage: ptr FLStringResult; outErrorPos: ptr csize_t; outError: var FLError): FLStringResult {.importc: "FLJSON5_ToJSON".} - -## Debugging function that returns a C string of JSON. Does not free the string's memory! -proc dump*(a1: FLValue): cstring {.importc: "FLDump".} - -## Debugging function that returns a C string of JSON. Does not free the string's memory! -proc dumpData*(data: FLSlice): cstring {.importc: "FLDumpData".} - - - -## ////// VALUE -## The core Fleece data type is FLValue: a reference to a value in Fleece-encoded data. -## An FLValue can represent any JSON type (plus binary data). -## -## - Scalar data types -- numbers, booleans, null, strings, data -- can be accessed -## using individual functions of the form `FLValue_As...`; these return the scalar value, -## or a default zero/false/null value if the value is not of that type. -## - Collections -- arrays and dictionaries -- have their own "subclasses": FLArray and -## FLDict. These have the same pointer values as an FLValue but are not type-compatible -## in C. To coerce an FLValue to a collection type, call FLValue_AsArray or FLValue_AsDict. -## If the value is not of that type, NULL is returned. (FLArray and FLDict are documented -## fully in their own sections.) -## -## It's always safe to pass a NULL value to an accessor; that goes for FLDict and FLArray -## as well as FLValue. The result will be a default value of that type, e.g. false or 0 -## or NULL, unless otherwise specified. - -## Types of Fleece values. Basically JSON, with the addition of Data (raw blob). -type - FLValueType* {.size: sizeof(cint).} = enum - kUndefined = -1, ## Type of a NULL pointer, i.e. no such value, like JSON `undefined`. Also the type of a value created by FLEncoder_WriteUndefined(). - kNull = 0, ## Equivalent to a JSON 'null' - kBoolean, ## A `true` or `false` value - kNumber, ## A numeric value, either integer or floating-point - kString, ## A string - kData, ## Binary data (no JSON equivalent) - kArray, ## An array of values - kDict ## A mapping of strings to values - - -## A timestamp, expressed as milliseconds since the Unix epoch (1-1-1970 midnight UTC.) -type - FLTimestamp* = distinct int64 - -## A value representing a missing timestamp; returned when a date cannot be parsed. -const - TimestampNone* = FLTimestamp(-0x7FFFFFFFFFFFFFFF'i64) - -## Returns the data type of an arbitrary FLValue. -## (If the parameter is a NULL pointer, returns `kFLUndefined`.) -proc getType*(a1: FLValue): FLValueType {.importc: "FLValue_GetType".} - -## Returns true if the value is non-NULL and represents an integer. -proc isInteger*(a1: FLValue): bool {.importc: "FLValue_IsInteger".} - -## Returns true if the value is non-NULL and represents an integer >= 2^63. Such a value can't -## be represented in C as an `int64_t`, only a `uint64_t`, so you should access it by calling -## `FLValueAsUnsigned`, _not_ FLValueAsInt, which would return an incorrect (negative) -## value. -proc isUnsigned*(a1: FLValue): bool {.importc: "FLValue_IsUnsigned".} - -## Returns true if the value is non-NULL and represents a 64-bit floating-point number. -proc isDouble*(a1: FLValue): bool {.importc: "FLValue_IsDouble".} - -## Returns a value coerced to boolean. This will be true unless the value is NULL (undefined), -## null, false, or zero. -proc asBool*(a1: FLValue): bool {.importc: "FLValue_AsBool".} - -## Returns a value coerced to an integer. True and false are returned as 1 and 0, and -## floating-point numbers are rounded. All other types are returned as 0. -## check for these by calling `FLValueIsUnsigned`. -proc asInt*(a1: FLValue): int64 {.importc: "FLValue_AsInt".} - -## Returns a value coerced to an unsigned integer. -## This is the same as `FLValueAsInt` except that it _can't_ handle negative numbers, but -## does correctly return large `uint64_t` values of 2^63 and up. -proc asUnsigned*(a1: FLValue): uint64 {.importc: "FLValue_AsUnsigned".} - -## Returns a value coerced to a 32-bit floating point number. -## True and false are returned as 1.0 and 0.0, and integers are converted to float. All other -## types are returned as 0.0. -## limitations of IEEE 32-bit float format. -proc asFloat*(a1: FLValue): cfloat {.importc: "FLValue_AsFloat".} - -## Returns a value coerced to a 32-bit floating point number. -## True and false are returned as 1.0 and 0.0, and integers are converted to float. All other -## types are returned as 0.0. -## the limitations of IEEE 32-bit float format. -proc asDouble*(a1: FLValue): cdouble {.importc: "FLValue_AsDouble".} - -## Returns the exact contents of a string value, or null for all other types. -proc asString*(a1: FLValue): FLString {.importc: "FLValue_AsString".} - -## Converts a value to a timestamp, in milliseconds since Unix epoch, or INT64_MIN on failure. -## - A string is parsed as ISO-8601 (standard JSON date format). -## - A number is interpreted as a timestamp and returned as-is. -proc asTimestamp*(a1: FLValue): FLTimestamp {.importc: "FLValue_AsTimestamp".} - -## Returns the exact contents of a data value, or null for all other types. -proc asData*(a1: FLValue): FLSlice {.importc: "FLValue_AsData".} - -## If a FLValue represents an array, returns it cast to FLArray, else NULL. -proc asArray*(a1: FLValue): FLArray {.importc: "FLValue_AsArray".} - -## If a FLValue represents a dictionary, returns it as an FLDict, else NULL. -proc asDict*(a1: FLValue): FLDict {.importc: "FLValue_AsDict".} - -## Returns a string representation of any scalar value. Data values are returned in raw form. -## Arrays and dictionaries don't have a representation and will return NULL. -proc toString*(a1: FLValue): FLStringResult {.importc: "FLValue_ToString".} - -## Compares two values for equality. This is a deep recursive comparison. -proc isEqual*(v1: FLValue; v2: FLValue): bool {.importc: "FLValue_IsEqual".} - -## If this value is mutable (and thus heap-based) its ref-count is incremented. -## Otherwise, this call does nothing. -proc retain*(a1: FLValue): FLValue {.importc: "FLValue_Retain".} - -## If this value is mutable (and thus heap-based) its ref-count is decremented, and if it -## reaches zero the value is freed. -## If the value is not mutable, this call does nothing. -proc release*(a1: FLValue) {.importc: "FLValue_Release".} -proc retain*(v: FLArray): FLArray {.inline.} = - return cast[FLArray](retain(cast[FLValue](v))) - -proc release*(v: FLArray) {.inline.} = - release(cast[FLValue](v)) - -proc retain*(v: FLDict): FLDict {.inline.} = - return cast[FLDict](retain(cast[FLValue](v))) - -proc release*(v: FLDict) {.inline.} = - release(cast[FLValue](v)) - -var kNullValue* {.importc: "kFLNullValue".}: FLValue - - - -## ////// VALUE SLOT -proc setNull*(a1: FLSlot) {.importc: "FLSlot_SetNull".} ## Stores a JSON null into a slot. - -proc set*(a1: FLSlot; a2: bool) {.importc: "FLSlot_SetBool".} ## Stores a boolean into a slot. - -proc set*(a1: FLSlot; a2: int64) {.importc: "FLSlot_SetInt".} ## Stores an integer into a slot. - -proc set*(a1: FLSlot; a2: uint64) {.importc: "FLSlot_SetUInt".} ## Stores an unsigned integer into a slot. - -proc set*(a1: FLSlot; a2: cfloat) {.importc: "FLSlot_SetFloat".} ## Stores a float into a slot. - -proc set*(a1: FLSlot; a2: cdouble) {.importc: "FLSlot_SetDouble".} ## Stores a double into a slot. - -proc set*(a1: FLSlot; a2: FLString) {.importc: "FLSlot_SetString".} ## Stores a string into a slot. - -proc setData*(a1: FLSlot; a2: FLSlice) {.importc: "FLSlot_SetData".} ## Stores a data blob into a slot. - -proc set*(a1: FLSlot; a2: FLValue) {.importc: "FLSlot_SetValue".} ## Stores an FLValue into a slot. - - - -## ////// ARRAY -## FLArray is a "subclass" of FLValue, representing values that are arrays. It's always OK to -## pass an FLArray to a function parameter expecting an FLValue, even though the compiler -## makes you use an explicit type-cast. It's safe to type-cast the other direction, from -## FLValue to FLArray, _only_ if you already know that the value is an array, e.g. by having -## called FLValue_GetType on it. But it's safer to call FLValue_AsArray instead, since it -## will return NULL if the value isn't an array. - -## Returns the number of items in an array, or 0 if the pointer is NULL. -proc count*(a1: FLArray): uint32 {.importc: "FLArray_Count".} - -## Returns true if an array is empty (or NULL). Depending on the array's representation, -## this can be faster than `FLArray_Count(a) == 0` -proc isEmpty*(a1: FLArray): bool {.importc: "FLArray_IsEmpty".} - -## If the array is mutable, returns it cast to FLMutableArray, else NULL. -proc asMutable*(a1: FLArray): FLMutableArray {.importc: "FLArray_AsMutable".} - -## Returns an value at an array index, or NULL if the index is out of range. -proc get*(a1: FLArray; index: uint32): FLValue {.importc: "FLArray_Get".} -var kEmptyArray* {.importc: "kFLEmptyArray".}: FLArray - -## Iterating an array typically looks like this: -## -## ``` -## FLArrayIterator iter; -## FLArrayIterator_Begin(theArray, &iter); -## FLValue value; -## while (NULL != (value = FLArrayIterator_GetValue(&iter))) { -## // ... -## FLArrayIterator_Next(&iter); -## } -## ``` - - -## Opaque array iterator. Declare one on the stack and pass its address to -## `FLArrayIteratorBegin`. -type - FLArrayIterator* {.bycopy.} = object - internalprivate1*: pointer - internalprivate2*: uint32 - internalprivate3*: bool - internalprivate4*: pointer - -## Initializes a FLArrayIterator struct to iterate over an array. -## Call FLArrayIteratorGetValue to get the first item, then FLArrayIteratorNext. -proc begin*(a1: FLArray; a2: ptr FLArrayIterator) {.importc: "FLArrayIterator_Begin".} - -## Returns the current value being iterated over. -proc getValue*(a1: ptr FLArrayIterator): FLValue {.importc: "FLArrayIterator_GetValue".} - -## Returns a value in the array at the given offset from the current value. -proc getValueAt*(a1: ptr FLArrayIterator; offset: uint32): FLValue {.importc: "FLArrayIterator_GetValueAt".} - -## Returns the number of items remaining to be iterated, including the current one. -proc getCount*(a1: ptr FLArrayIterator): uint32 {.importc: "FLArrayIterator_GetCount".} - -## Advances the iterator to the next value, or returns false if at the end. -proc next*(a1: ptr FLArrayIterator): bool {.importc: "FLArrayIterator_Next".} - - - -## ////// MUTABLE ARRAY - - -type - CopyFlags* {.size: sizeof(cint).} = enum - DefaultCopy = 0, DeepCopy = 1, CopyImmutables = 2, DeepCopyImmutables = 3 - - -## Creates a new mutable FLArray that's a copy of the source FLArray. -## Its initial ref-count is 1, so a call to FLMutableArray_Release will free it. -## -## Copying an immutable FLArray is very cheap (only one small allocation) unless the flag -## kFLCopyImmutables is set. -## -## Copying a mutable FLArray is cheap if it's a shallow copy, but if `deepCopy` is true, -## nested mutable Arrays and Dicts are also copied, recursively; if kFLCopyImmutables is -## also set, immutable values are also copied. -## -## If the source FLArray is NULL, then NULL is returned. -proc mutableCopy*(a1: FLArray; a2: CopyFlags): FLMutableArray {.importc: "FLArray_MutableCopy".} - -## Creates a new empty mutable FLArray. -## Its initial ref-count is 1, so a call to FLMutableArray_Free will free it. -proc newMutableArray*(): FLMutableArray {.importc: "FLMutableArray_New".} - -## Increments the ref-count of a mutable FLArray. -proc retain*(d: FLMutableArray): FLMutableArray {.inline.} = - return cast[FLMutableArray](retain(cast[FLValue](d))) - -## Decrements the refcount of (and possibly frees) a mutable FLArray. -proc release*(d: FLMutableArray) {.inline.} = - release(cast[FLValue](d)) - -## If the FLArray was created by FLArray_MutableCopy, returns the original source FLArray. -proc getSource*(a1: FLMutableArray): FLArray {.importc: "FLMutableArray_GetSource".} - -## Returns true if the FLArray has been changed from the source it was copied from. -proc isChanged*(a1: FLMutableArray): bool {.importc: "FLMutableArray_IsChanged".} - -## Lets you store a value into a FLMutableArray, by returning a \ref FLSlot that you can call -## a function like \ref FLSlot_SetInt on. -proc set*(a1: FLMutableArray; index: uint32): FLSlot {.importc: "FLMutableArray_Set".} - -## Appends a null value to a FLMutableArray and returns a \ref FLSlot that you can call -## to store something else in the new value. -proc append*(a1: FLMutableArray): FLSlot {.importc: "FLMutableArray_Append".} - -## Inserts a contiguous range of JSON `null` values into the array. -proc insert*(array: FLMutableArray; firstIndex: uint32; count: uint32) {.importc: "FLMutableArray_Insert".} - -## Removes contiguous items from the array. -proc remove*(array: FLMutableArray; firstIndex: uint32; count: uint32) {.importc: "FLMutableArray_Remove".} - -## Changes the size of an array. -## If the new size is larger, the array is padded with JSON `null` values. -## If it's smaller, values are removed from the end. -proc resize*(array: FLMutableArray; size: uint32) {.importc: "FLMutableArray_Resize".} - -## Convenience function for getting an array-valued property in mutable form. -## - If the value for the key is not an array, returns NULL. -## - If the value is a mutable array, returns it. -## - If the value is an immutable array, this function makes a mutable copy, assigns the -## copy as the property value, and returns the copy. -proc getMutableArray*(a1: FLMutableArray; index: uint32): FLMutableArray {.importc: "FLMutableArray_GetMutableArray".} - -## Convenience function for getting an array-valued property in mutable form. -## - If the value for the key is not an array, returns NULL. -## - If the value is a mutable array, returns it. -## - If the value is an immutable array, this function makes a mutable copy, assigns the -## copy as the property value, and returns the copy. -proc getMutableDict*(a1: FLMutableArray; index: uint32): FLMutableDict {.importc: "FLMutableArray_GetMutableDict".} - - - -## ////// DICT - -## Returns the number of items in a dictionary, or 0 if the pointer is NULL. -proc count*(a1: FLDict): uint32 {.importc: "FLDict_Count".} - -## Returns true if a dictionary is empty (or NULL). Depending on the dictionary's -## representation, this can be faster than `FLDict_Count(a) == 0` -proc isEmpty*(a1: FLDict): bool {.importc: "FLDict_IsEmpty".} - -## If the dictionary is mutable, returns it cast to FLMutableDict, else NULL. -proc asMutable*(a1: FLDict): FLMutableDict {.importc: "FLDict_AsMutable".} - -## Looks up a key in a dictionary, returning its value. -## Returns NULL if the value is not found or if the dictionary is NULL. -proc get*(a1: FLDict; keyString: FLSlice): FLValue {.importc: "FLDict_Get".} -var kEmptyDict* {.importc: "kFLEmptyDict".}: FLDict - -## Iterating a dictionary typically looks like this: -## -## ``` -## FLDictIterator iter; -## FLDictIterator_Begin(theDict, &iter); -## FLValue value; -## while (NULL != (value = FLDictIterator_GetValue(&iter))) { -## FLString key = FLDictIterator_GetKeyString(&iter); -## // ... -## FLDictIterator_Next(&iter); -## } -## ``` -## -## Opaque dictionary iterator. Declare one on the stack, and pass its address to -## FLDictIterator_Begin. -type - FLDictIterator* {.bycopy.} = object - internalprivate1*: pointer - internalprivate2*: uint32 - internalprivate3*: bool - internalprivate4*: array[4, pointer] - internalprivate5*: cint - -## Initializes a FLDictIterator struct to iterate over a dictionary. -## Call FLDictIterator_GetKey and FLDictIterator_GetValue to get the first item, -## then FLDictIterator_Next. -proc begin*(a1: FLDict; a2: ptr FLDictIterator) {.importc: "FLDictIterator_Begin".} - -## Returns the current key being iterated over. This FLValue will be a string or an integer. -proc getKey*(a1: ptr FLDictIterator): FLValue {.importc: "FLDictIterator_GetKey".} - -## Returns the current key's string value. -proc getKeyString*(a1: ptr FLDictIterator): FLString {.importc: "FLDictIterator_GetKeyString".} - -## Returns the current value being iterated over. -proc getValue*(a1: ptr FLDictIterator): FLValue {.importc: "FLDictIterator_GetValue".} - -## Returns the number of items remaining to be iterated, including the current one. -proc getCount*(a1: ptr FLDictIterator): uint32 {.importc: "FLDictIterator_GetCount".} - -## Advances the iterator to the next value, or returns false if at the end. -proc next*(a1: ptr FLDictIterator): bool {.importc: "FLDictIterator_Next".} - -## Cleans up after an iterator. Only needed if (a) the dictionary is a delta, and -## (b) you stop iterating before the end (i.e. before FLDictIterator_Next returns false.) -proc `end`*(a1: ptr FLDictIterator) {.importc: "FLDictIterator_End".} - -## Opaque key for a dictionary. You are responsible for creating space for these; they can -## go on the stack, on the heap, inside other objects, anywhere. -## Be aware that the lookup operations that use these will write into the struct to store -## "hints" that speed up future searches. -type - FLDictKey* {.bycopy.} = object - internalprivate1*: FLSlice - internalprivate2*: pointer - internalprivate3*: uint32 - private4*: uint32 - private5*: bool - - -## Initializes an FLDictKey struct with a key string. -## use! (The FLDictKey stores a pointer to the string, but does not copy it.) -proc init*(string: FLSlice): FLDictKey {.importc: "FLDictKey_Init".} - -## Returns the string value of the key (which it was initialized with.) -proc getString*(a1: ptr FLDictKey): FLString {.importc: "FLDictKey_GetString".} - -## Looks up a key in a dictionary using an FLDictKey. If the key is found, "hint" data will -## be stored inside the FLDictKey that will speed up subsequent lookups. -proc getWithKey*(a1: FLDict; a2: ptr FLDictKey): FLValue {.importc: "FLDict_GetWithKey".} - - - -## ////// MUTABLE DICT - -## Creates a new mutable FLDict that's a copy of the source FLDict. -## Its initial ref-count is 1, so a call to FLMutableDict_Release will free it. -## -## Copying an immutable FLDict is very cheap (only one small allocation.) The `deepCopy` flag -## is ignored. -## -## Copying a mutable FLDict is cheap if it's a shallow copy, but if `deepCopy` is true, -## nested mutable Dicts and Arrays are also copied, recursively. -## -## If the source dict is NULL, then NULL is returned. -proc mutableCopy*(source: FLDict; a2: CopyFlags): FLMutableDict {.importc: "FLDict_MutableCopy".} - -## Creates a new empty mutable FLDict. -## Its initial ref-count is 1, so a call to FLMutableDict_Free will free it. -proc newMutableDict*(): FLMutableDict {.importc: "FLMutableDict_New".} - -## Increments the ref-count of a mutable FLDict. -proc retain*(d: FLMutableDict): FLMutableDict {.inline.} = - return cast[FLMutableDict](retain(cast[FLValue](d))) - -## Decrements the refcount of (and possibly frees) a mutable FLDict. -proc release*(d: FLMutableDict) {.inline.} = - release(cast[FLValue](d)) - -## If the FLDict was created by FLDict_MutableCopy, returns the original source FLDict. -proc getSource*(a1: FLMutableDict): FLDict {.importc: "FLMutableDict_GetSource".} - -## Returns true if the FLDict has been changed from the source it was copied from. -proc isChanged*(a1: FLMutableDict): bool {.importc: "FLMutableDict_IsChanged".} - -## Returns the FLSlot storing the key's value, adding a new one if needed (with a null value.) -## To set the value itself, call one of the FLSlot functions, e.g. \ref FLSlot_SetInt. -proc set*(nonnull: FLMutableDict; key: FLString): FLSlot {.importc: "FLMutableDict_Set".} - -## Removes the value for a key. -proc remove*(a1: FLMutableDict; key: FLString) {.importc: "FLMutableDict_Remove".} - -## Removes all keys and values. -proc removeAll*(a1: FLMutableDict) {.importc: "FLMutableDict_RemoveAll".} - -## Convenience function for getting an array-valued property in mutable form. -## - If the value for the key is not an array, returns NULL. -## - If the value is a mutable array, returns it. -## - If the value is an immutable array, this function makes a mutable copy, assigns the -## copy as the property value, and returns the copy. -proc getMutableArray*(a1: FLMutableDict; key: FLString): FLMutableArray {.importc: "FLMutableDict_GetMutableArray".} - -## Convenience function for getting a dict-valued property in mutable form. -## - If the value for the key is not a dict, returns NULL. -## - If the value is a mutable dict, returns it. -## - If the value is an immutable dict, this function makes a mutable copy, assigns the -## copy as the property value, and returns the copy. -proc getMutableDict*(a1: FLMutableDict; key: FLString): FLMutableDict {.importc: "FLMutableDict_GetMutableDict".} - - - -## ////// DEEP ITERATOR - -## A deep iterator traverses every value contained in a dictionary, in depth-first order. -## You can skip any nested collection by calling FLDeepIterator_SkipChildren. -type - DeepIterator* = ptr object ## A reference to a deep iterator. - -## Creates a FLDeepIterator to iterate over a dictionary. -## Call FLDeepIterator_GetKey and FLDeepIterator_GetValue to get the first item, -## then FLDeepIterator_Next. -proc newDeepIterator*(a1: FLValue): DeepIterator {.importc: "FLDeepIterator_New".} -proc free*(a1: DeepIterator) {.importc: "FLDeepIterator_Free".} - -## Returns the current value being iterated over. or NULL at the end of iteration. -proc getValue*(a1: DeepIterator): FLValue {.importc: "FLDeepIterator_GetValue".} - -## Returns the key of the current value, or an empty slice if not in a dictionary. -proc getKey*(a1: DeepIterator): FLSlice {.importc: "FLDeepIterator_GetKey".} - -## Returns the array index of the current value, or 0 if not in an array. -proc getIndex*(a1: DeepIterator): uint32 {.importc: "FLDeepIterator_GetIndex".} - -## Returns the current depth in the hierarchy, starting at 1 for the top-level children. -proc getDepth*(a1: DeepIterator): csize_t {.importc: "FLDeepIterator_GetDepth".} - -## Tells the iterator to skip the children of the current value. -proc skipChildren*(a1: DeepIterator) {.importc: "FLDeepIterator_SkipChildren".} - -## Advances the iterator to the next value, or returns false if at the end. -proc next*(a1: DeepIterator): bool {.importc: "FLDeepIterator_Next".} -type - PathComponent* {.bycopy.} = object - key*: FLSlice ## FLDict key, or kFLSliceNull if none - index*: uint32 ## FLArray index, only if there's no key - -## Returns the path as an array of FLPathComponents. -proc getPath*(a1: DeepIterator; outPath: ptr ptr PathComponent; outDepth: ptr csize_t) {.importc: "FLDeepIterator_GetPath".} - -## Returns the current path in JavaScript format. -proc getPathString*(a1: DeepIterator): FLSliceResult {.importc: "FLDeepIterator_GetPathString".} - -## Returns the current path in JSONPointer format (RFC 6901). -proc getJSONPointer*(a1: DeepIterator): FLSliceResult {.importc: "FLDeepIterator_GetJSONPointer".} - - - -## ////// PATH - -## An FLKeyPath Describes a location in a Fleece object tree, as a path from the root that follows -## dictionary properties and array elements. -## It's similar to a JSONPointer or an Objective-C FLKeyPath, but simpler (so far.) -## The path is compiled into an efficient form that can be traversed quickly. -## -## It looks like `foo.bar[2][-3].baz` -- that is, properties prefixed with a `.`, and array -## indexes in brackets. (Negative indexes count from the end of the array.) -## -## A leading JSONPath-like `$.` is allowed but ignored. -## -## A '\' can be used to escape a special character ('.', '[' or '$') at the start of a -## property name (but not yet in the middle of a name.) -## -type - FLKeyPath* = ptr object ## A reference to a key path. - -## Creates a new FLKeyPath object by compiling a path specifier string. -proc newKeyPath*(specifier: FLSlice; error: var FLError): FLKeyPath {.importc: "FLKeyPath_New".} - -## Frees a compiled FLKeyPath object. (It's ok to pass NULL.) -proc free*(a1: FLKeyPath) {.importc: "FLKeyPath_Free".} - -## Evaluates a compiled key-path for a given Fleece root object. -proc eval*(a1: FLKeyPath; root: FLValue): FLValue {.importc: "FLKeyPath_Eval".} - -## Evaluates a key-path from a specifier string, for a given Fleece root object. -## If you only need to evaluate the path once, this is a bit faster than creating an -## FLKeyPath object, evaluating, then freeing it. -proc evalOnce*(specifier: FLSlice; root: FLValue; error: var FLError): FLValue {.importc: "FLKeyPath_EvalOnce".} - - - -## ////// SHARED KEYS - -proc createSharedKeys*(): SharedKeys {.importc: "FLSharedKeys_Create".} -proc retain*(a1: SharedKeys): SharedKeys {.importc: "FLSharedKeys_Retain".} -proc release*(a1: SharedKeys) {.importc: "FLSharedKeys_Release".} -proc createSharedKeysFromStateData*(a1: FLSlice): SharedKeys {.importc: "FLSharedKeys_CreateFromStateData".} -proc getStateData*(a1: SharedKeys): FLSliceResult {.importc: "FLSharedKeys_GetStateData".} -proc encode*(a1: SharedKeys; a2: FLString; add: bool): cint {.importc: "FLSharedKeys_Encode".} -proc decode*(a1: SharedKeys; key: cint): FLString {.importc: "FLSharedKeys_Decode".} -proc count*(a1: SharedKeys): cuint {.importc: "FLSharedKeys_Count".} - - - -## ////// ENCODER - -## An FLEncoder generates encoded Fleece or JSON data. It's sort of a structured output stream, -## with nesting. There are functions for writing every type of scalar value, and for beginning -## and ending collections. To write a collection you begin it, write its values, then end it. -## (Of course a value in a collection can itself be another collection.) When writing a -## dictionary, you have to call writeKey before writing each value. -## -type - FLEncoder* = ptr object ## A reference to an encoder. - -## Output formats a FLEncoder can generate. -type - EncoderFormat* {.size: sizeof(cint).} = enum - Fleece, ## Fleece encoding - JSON, ## JSON encoding - JSON5 ## [JSON5](http://json5.org), an extension of JSON with a more readable syntax - - -## Creates a new encoder, for generating Fleece data. Call FLEncoder_Free when done. -proc newEncoder*(): FLEncoder {.importc: "FLEncoder_New".} - -## Creates a new encoder, allowing some options to be customized. -## as a single shared value. This saves space but makes encoding slightly slower. -## You should only turn this off if you know you're going to be writing large numbers -## of non-repeated strings. (Default is true) -proc newEncoderWithOptions*(format: EncoderFormat; reserveSize: csize_t; uniqueStrings: bool): FLEncoder {.importc: "FLEncoder_NewWithOptions".} - -## Creates a new Fleece encoder that writes to a file, not to memory. -proc newEncoderWritingToFile*(a1: ptr File; uniqueStrings: bool): FLEncoder {.importc: "FLEncoder_NewWritingToFile".} - -## Frees the space used by an encoder. -proc free*(a1: FLEncoder) {.importc: "FLEncoder_Free".} - -## Tells the encoder to use a shared-keys mapping when encoding dictionary keys. -proc setSharedKeys*(a1: FLEncoder; a2: SharedKeys) {.importc: "FLEncoder_SetSharedKeys".} - -## Associates an arbitrary user-defined value with the encoder. -proc setExtraInfo*(a1: FLEncoder; info: pointer) {.importc: "FLEncoder_SetExtraInfo".} - -## Returns the user-defined value associated with the encoder; NULL by default. -proc getExtraInfo*(a1: FLEncoder): pointer {.importc: "FLEncoder_GetExtraInfo".} - -## Tells the encoder to logically append to the given Fleece document, rather than making a -## standalone document. Any calls to FLEncoder_WriteValue() where the value points inside the -## base data will write a pointer back to the original value. -## The resulting data returned by FLEncoder_FinishDoc() will *NOT* be standalone; it can only -## be used by first appending it to the base data. -## just create a pointer back to the original. But the encoder has to scan the -## base for strings first. -## flag. This allows them to be resolved using the `FLResolver_Begin` function, -## so that when the delta is used the base document can be anywhere in memory, -## not just immediately preceding the delta document. -proc amend*(e: FLEncoder; base: FLSlice; reuseStrings: bool; externPointers: bool) {.importc: "FLEncoder_Amend".} - -## Returns the `base` value passed to FLEncoder_Amend. -proc getBase*(a1: FLEncoder): FLSlice {.importc: "FLEncoder_GetBase".} - -## Tells the encoder not to write the two-byte Fleece trailer at the end of the data. -## This is only useful for certain special purposes. -proc suppressTrailer*(a1: FLEncoder) {.importc: "FLEncoder_SuppressTrailer".} - -## Resets the state of an encoder without freeing it. It can then be reused to encode -## another value. -proc reset*(a1: FLEncoder) {.importc: "FLEncoder_Reset".} - -## Returns the number of bytes encoded so far. -proc bytesWritten*(a1: FLEncoder): csize_t {.importc: "FLEncoder_BytesWritten".} - -## Returns the byte offset in the encoded data where the next value will be written. -## (Due to internal buffering, this is not the same as FLEncoder_BytesWritten.) -proc getNextWritePos*(a1: FLEncoder): csize_t {.importc: "FLEncoder_GetNextWritePos".} - -## result on error. The actual error is attached to the encoder and can be accessed by calling -## FLEncoder_GetError or FLEncoder_End. -## -## After an error occurs, the encoder will ignore all subsequent writes. -## Writes a `null` value to an encoder. (This is an explicitly-stored null, like the JSON -## `null`, not the "undefined" value represented by a NULL FLValue pointer.) -proc writeNull*(a1: FLEncoder): bool {.importc: "FLEncoder_WriteNull".} - -## Writes an `undefined` value to an encoder. (Its value when read will not be a `NULL` -## pointer, but it can be recognized by `FLValue_GetType` returning `kFLUndefined`.) -## An undefined dictionary value should be written simply by skipping the key and value. -proc writeUndefined*(a1: FLEncoder): bool {.importc: "FLEncoder_WriteUndefined".} - -## Writes a boolean value (true or false) to an encoder. -proc writeBool*(a1: FLEncoder; a2: bool): bool {.importc: "FLEncoder_WriteBool".} - -## Writes an integer to an encoder. The parameter is typed as `int64_t` but you can pass any -## integral type (signed or unsigned) except for huge `uint64_t`s. -## The number will be written in a compact form that uses only as many bytes as necessary. -proc writeInt*(a1: FLEncoder; a2: int64): bool {.importc: "FLEncoder_WriteInt".} - -## Writes an unsigned integer to an encoder. -## 64-bit integers greater than or equal to 2^63, which can't be represented as int64_t. -proc writeUInt*(a1: FLEncoder; a2: uint64): bool {.importc: "FLEncoder_WriteUInt".} - -## Writes a 32-bit floating point number to an encoder. -## represented exactly as an integer, it'll be encoded as an integer to save space. This is -## transparent to the reader, since if it requests the value as a float it'll be returned -## as floating-point. -proc writeFloat*(a1: FLEncoder; a2: cfloat): bool {.importc: "FLEncoder_WriteFloat".} - -## Writes a 64-bit floating point number to an encoder. -## as an integer, if this can be done without losing precision. For example, 123.0 will be -## written as an integer, and 123.75 as a float.) -proc writeDouble*(a1: FLEncoder; a2: cdouble): bool {.importc: "FLEncoder_WriteDouble".} - -## Writes a string to an encoder. The string must be UTF-8-encoded and must not contain any -## zero bytes. -proc writeString*(a1: FLEncoder; a2: FLString): bool {.importc: "FLEncoder_WriteString".} - -## Writes a timestamp to an encoder, as an ISO-8601 date string. -## metadata that distinguishes it as a date. It's just a string.) -proc writeDateString*(encoder: FLEncoder; ts: FLTimestamp; asUTC: bool): bool {.importc: "FLEncoder_WriteDateString".} - -## Writes a binary data value (a blob) to an encoder. This can contain absolutely anything -## including null bytes. -## If the encoder is generating JSON, the blob will be written as a base64-encoded string. -proc writeData*(a1: FLEncoder; a2: FLSlice): bool {.importc: "FLEncoder_WriteData".} - -## Writes raw data directly to the encoded output. -## (This is not the same as FLEncoder_WriteData, which safely encodes a blob.) -## it's quite unsafe, and only used for certain advanced purposes. -proc writeRaw*(a1: FLEncoder; a2: FLSlice): bool {.importc: "FLEncoder_WriteRaw".} - -## Begins writing an array value to an encoder. This pushes a new state where each -## subsequent value written becomes an array item, until FLEncoder_EndArray is called. -## of the array, providing it here speeds up encoding slightly. If you don't know, -## just use zero. -proc beginArray*(a1: FLEncoder; reserveCount: csize_t): bool {.importc: "FLEncoder_BeginArray".} - -## Ends writing an array value; pops back the previous encoding state. -proc endArray*(a1: FLEncoder): bool {.importc: "FLEncoder_EndArray".} - -## Begins writing a dictionary value to an encoder. This pushes a new state where each -## subsequent key and value written are added to the dictionary, until FLEncoder_EndDict is -## called. -## Before adding each value, you must call FLEncoder_WriteKey (_not_ FLEncoder_WriteString!), -## to write the dictionary key. -## of the dictionary, providing it here speeds up encoding slightly. If you don't know, -## just use zero. -proc beginDict*(a1: FLEncoder; reserveCount: csize_t): bool {.importc: "FLEncoder_BeginDict".} - -## Specifies the key for the next value to be written to the current dictionary. -proc writeKey*(a1: FLEncoder; a2: FLString): bool {.importc: "FLEncoder_WriteKey".} - -## Specifies the key for the next value to be written to the current dictionary. -## The key is given as a FLValue, which must be a string or integer. -proc writeKeyValue*(a1: FLEncoder; a2: FLValue): bool {.importc: "FLEncoder_WriteKeyValue".} - -## Ends writing a dictionary value; pops back the previous encoding state. -proc endDict*(a1: FLEncoder): bool {.importc: "FLEncoder_EndDict".} - -## Writes a Fleece FLValue to an FLEncoder. -proc writeValue*(a1: FLEncoder; a2: FLValue): bool {.importc: "FLEncoder_WriteValue".} - -## Parses JSON data and writes the object(s) to the encoder. (This acts as a single write, -## like WriteInt; it's just that the value written is likely to be an entire dictionary of -## array.) -proc convertJSON*(a1: FLEncoder; json: FLSlice): bool {.importc: "FLEncoder_ConvertJSON".} - -## Finishes encoding the current item, and returns its offset in the output data. -proc finishItem*(a1: FLEncoder): csize_t {.importc: "FLEncoder_FinishItem".} - -## Ends encoding; if there has been no error, it returns the encoded Fleece data packaged in -## an FLDoc. (This function does not support JSON encoding.) -## This does not free the FLEncoder; call FLEncoder_Free (or FLEncoder_Reset) next. -proc finishDoc*(a1: FLEncoder; a2: var FLError): FLDoc {.importc: "FLEncoder_FinishDoc".} - -## Ends encoding; if there has been no error, it returns the encoded data, else null. -## This does not free the FLEncoder; call FLEncoder_Free (or FLEncoder_Reset) next. -proc finish*(e: FLEncoder; outError: var FLError): FLSliceResult {.importc: "FLEncoder_Finish".} - -## Returns the error code of an encoder, or NoError (0) if there's no error. -proc getError*(a1: FLEncoder): FLError {.importc: "FLEncoder_GetError".} - -## Returns the error message of an encoder, or NULL if there's no error. -proc getErrorMessage*(a1: FLEncoder): cstring {.importc: "FLEncoder_GetErrorMessage".} - - - -## ////// JSON DELTA COMPRESSION - -## These functions implement a fairly-efficient "delta" encoding that encapsulates the changes -## needed to transform one Fleece value into another. The delta is expressed in JSON form. -## -## A delta can be stored or transmitted -## as an efficient way to produce the second value, when the first is already present. Deltas -## are frequently used in version-control systems and efficient network protocols. - - -## Returns JSON that encodes the changes to turn the value `old` into `nuu`. -## (The format is documented in Fleece.md, but you should treat it as a black box.) -## (extremely unlikely) failure. -proc createJSONDelta*(old: FLValue; nuu: FLValue): FLSliceResult {.importc: "FLCreateJSONDelta".} - -## Writes JSON that describes the changes to turn the value `old` into `nuu`. -## (The format is documented in Fleece.md, but you should treat it as a black box.) -## `FLEncoder_NewWithOptions`, with JSON or JSON5 format. -proc encodeJSONDelta*(old: FLValue; nuu: FLValue; jsonEncoder: FLEncoder): bool {.importc: "FLEncodeJSONDelta".} - -## Applies the JSON data created by `CreateJSONDelta` to the value `old`, which must be equal -## to the `old` value originally passed to `FLCreateJSONDelta`, and returns a Fleece document -## equal to the original `nuu` value. -## equal to the `old` value used when creating the `jsonDelta`. -proc applyJSONDelta*(old: FLValue; jsonDelta: FLSlice; error: var FLError): FLSliceResult {.importc: "FLApplyJSONDelta".} - -## Applies the (parsed) JSON data created by `CreateJSONDelta` to the value `old`, which must be -## equal to the `old` value originally passed to `FLCreateJSONDelta`, and writes the corresponding -## `nuu` value to the encoder. -## equal to the `old` value used when creating the `jsonDelta`. -## supported.) -proc encodeApplyingJSONDelta*(old: FLValue; jsonDelta: FLSlice; encoder: FLEncoder): bool {.importc: "FLEncodeApplyingJSONDelta".} - -{.pop.} diff --git a/bindings/nim/src/CouchbaseLite/private/gen-bindings.sh b/bindings/nim/src/CouchbaseLite/private/gen-bindings.sh deleted file mode 100755 index 951d1d08..00000000 --- a/bindings/nim/src/CouchbaseLite/private/gen-bindings.sh +++ /dev/null @@ -1,23 +0,0 @@ -#! /bin/bash -e -# -# NOTE: c2nim can be obtained from https://github.com/nim-lang/c2nim -# -# This script does not replace the binding source files cbl.nim and cbl.nim; -# instead it creates new ones, cbl-new.nim and fl-new.nim. -# The binding files started out as output from this tool, but have been hand-edited to work -# around limitations of c2nim. The files produced by this script will _not_ work. -# -# The best procedure for updating bindings would be to run this script before and after changing -# the C headers, compare the old and new generated files, and apply those diffs by hand to the -# bindings. - -SCRIPT_DIR=`dirname $0` -cd "$SCRIPT_DIR" - -ROOT="../../../../.." -INCLUDE="$ROOT/include/cbl" -FLEECE="$ROOT/vendor/couchbase-lite-core/vendor/fleece/API/fleece" - -c2nim --concat -o:fl-new.nim cbl.c2nim --dynlib:'"CouchbaseLite.dylib"' --nep1 "$FLEECE/FLSlice.h" "$FLEECE/Fleece.h" - -c2nim --concat -o:cbl-new.nim cbl.c2nim --dynlib:'"CouchbaseLite.dylib"' --nep1 "$INCLUDE"/CBLBase.h "$INCLUDE"/CBLDatabase.h "$INCLUDE"/CBLDocument.h "$INCLUDE"/CBLBlob.h "$INCLUDE"/CBLLog.h "$INCLUDE"/CBLQuery.h "$INCLUDE"/CBLReplicator.h diff --git a/bindings/nim/src/CouchbaseLite/query.nim b/bindings/nim/src/CouchbaseLite/query.nim deleted file mode 100644 index c4b3cad7..00000000 --- a/bindings/nim/src/CouchbaseLite/query.nim +++ /dev/null @@ -1,150 +0,0 @@ -# Couchbase Lite Query class -# -# Copyright (c) 2020 Couchbase, Inc All rights reserved. -# -# 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 CouchbaseLite/[database, errors, fleece] -import CouchbaseLite/private/cbl -import CouchbaseLite/private/fl # for slice utilities - -{.experimental: "notnil".} - - -type - QueryObj {.requiresInit.} = object - handle: CBLQuery not nil - Query* = ref QueryObj not nil - ## A compiled database query. - - QueryLanguage* {.pure.} = enum - ## A query language syntax. - JSON, ## JSON schema: github.com/couchbase/couchbase-lite-core/wiki/JSON-Query-Schema - N1QL ## N1QL syntax: docs.couchbase.com/server/6.0/n1ql/n1ql-language-reference/ - - QuerySyntaxError* = ref object of CouchbaseLiteError - ## Exception thrown by ``Query.newQuery``. It contains the byte offset of - ## the approximate position of the error in the input string. - byteOffset*: int - - Row* {.requiresInit.} = object - ## A result row from running a query. A collection that contains one - ## "column" value for each item specified in the query's ``SELECT`` clause. - ## The columns can be accessed by either position or name. - results: CBLResultSet - -proc `=destroy`(d: var QueryObj) = - release(d.handle) - -proc `=`(dst: var QueryObj, src: QueryObj) {.error.} = - echo "can't copy a query" - - -proc newQuery*(db: Database; str: string; - language: QueryLanguage = N1QL): Query = - ## Creates a new Query by compiling the input string. - ## This is fast, but not instantaneous. If you need to run the same query - ## many times, keep the Query instance around instead of compiling it each - ## time. If you need to run related queries with only some values different, - ## create one query with placeholder parameter(s), and substitute the desired - ## value(s) by setting the ``parameters`` property each time you run the - ## query. - var errPos: cint - var err: CBLError - let q = newQuery(db.internal_handle, CBLQueryLanguage(language), str, - addr errPos, err) - if q == nil: - if err.domain == CBLDomain and err.code == int( - CBLErrorCode.ErrorInvalidQuery): - raise QuerySyntaxError(code: ErrorCode.InvalidQuery, - msg: "Query syntax error", byteOffset: errPos) - else: - throw(err) - else: - return Query(handle: q) - -proc explain*(query: Query): string = - ## Returns information about the query, including the translated SQLite form, - ## and the search strategy. You can use this to help optimize the query: the - ## word ``SCAN`` in the strategy indicates a linear scan of the entire - ## database, which should be avoided by adding an index. The strategy will - ## also show which index(es), if any, are used. - query.handle.explain().toString() - -proc columnCount*(query: Query): uint = - ## The number of columns in each result ``Row``. Equal to the number of items - ## specified in the query string's ``SELECT`` clause. - query.handle.columnCount() - -proc columnNames*(query: Query): seq[string] = - ## The names of the result columns, in order. - for i in 0..query.columnCount: - result.add(query.handle.columnName(cuint(i)).toString()) - -proc parameters*(query: Query): Dict = - ## The query's current parameter bindings, if any. - query.handle.parameters() - -proc `parameters=`*(query: Query, parameters: Dict) = - ## Assigns values to the query's parameters. These values will be substited - ## for those parameters whenever the query is executed, until they are next - ## assigned. - ## - ## A parameter named e.g. ``PARAM`` is specified in the query source as - ## ``$PARAM`` (N1QL) or ``["$PARAM"]`` (JSON). In this example, the - ## `parameters` dictionary to this call should have a key `PARAM` that maps - ## to the value of the parameter. - query.handle.setParameters(parameters) - -proc `parameters=`*(query: Query, json: string) = - ## Assigns values to the query's parameters, in the form of a JSON string - ## containing an object whose keys are the parameter names. - if not query.handle.setParametersAsJSON(json): - raise errors.FleeceError(code: FleeceErrorCode.JSONError, - msg: "Invalid JSON for parameters") - - -iterator execute*(query: Query): Row = - ## Runs the query, iterating over the result rows. - var err: CBLError - let rs = query.handle.execute(err) - if rs == nil: - throw(err) - defer: release(rs) - while next(rs): - yield Row(results: rs) - -proc column*(row: Row, i: uint): Value = - ## The value of a column given its (zero-based) index. - row.results.valueAtIndex(cuint(i)) - -proc column*(row: Row, name: string): Value = - ## The value of a column given its name. - row.results.valueForKey(name) - -proc `[]`*(row: Row, i: uint): Value = - ## The value of a column given its (zero-based) index. - row.column(i) - -proc `[]`*(row: Row, name: string): Value = - ## The value of a column given its name. - row.column(name) - -proc asArray*(row: Row): Array = - ## An array of all the column values. - rowArray(row.results) - -proc asDict*(row: Row): Dict = - ## A Dict of all the column names/values. - rowDict(row.results) diff --git a/bindings/nim/src/CouchbaseLite/replicator.nim b/bindings/nim/src/CouchbaseLite/replicator.nim deleted file mode 100644 index d546d4f2..00000000 --- a/bindings/nim/src/CouchbaseLite/replicator.nim +++ /dev/null @@ -1,232 +0,0 @@ -# Couchbase Lite replicator API -# -# Copyright (c) 2020 Couchbase, Inc All rights reserved. -# -# 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 CouchbaseLite/[database, document, errors, listener] -import CouchbaseLite/private/cbl - -import httpcore -import options -import sets -import uri - -{.experimental: "notnil".} - - -## WARNING: THIS API IS UNIMPLEMENTED SO FAR - - -#======== CONFIGURATION - - -type - EndpointType* = enum - WithURL, - WithLocalDB - Endpoint* = object - ## Represents the location of a database to replicate with. - case type*: EndpointType: - of WithURL: url*: Url ## WebSocket URL ("ws:" or "wss:") of remote database - of WithLocalDB: db*: Database ## Local database (available only in Enterprise Edition) - - AuthenticatorType* = enum - None, - Basic, - Session, - Cookie - Authenticator* = object - ## Represents authentication credentials for a remote server. - case type*: AuthenticatorType: - of None: discard - of Basic: username*, password*: string - of Session: sessionID*: string - of Cookie: name*, value*: string - - ReplicatorType* = enum - ## Direction of replication: push, pull, or both. - PushAndPull = 0 - Push - Pull - - ProxyType* = enum HTTP, HTTPS - ProxySettings* = object - ## HTTP client proxy settings for the replicator. - proxyType*: ProxyType - hostname*: string - port*: uint16 - username*: string - password*: string - - ReplicationFilter* = proc(document: Document; isDeleted: bool): bool - ## A callback that can decide whether a particular document should be pushed or pulled. - ConflictResolver* = proc(documentID: string; local, - remote: Document): Document - ## Conflict-resolution callback for use in replications. This callback will - ## be invoked when the replicator finds a newer server-side revision of a - ## document that also has local changes. The local and remote changes must - ## be resolved before the document can be pushed to the server. - - ReplicatorConfiguration* = object - ## The configuration of a replicator - database*: Database ## The database to replicate - endpoint*: Endpoint ## The address of the other database to replicate with - replicatorType*: ReplicatorType ## Push, pull or both - continuous*: bool ## Continuous replication? - - authenticator*: Authenticator ## Authentication credentials, if needed - proxy*: Option[ProxySettings] ## HTTP client proxy settings - headers*: HttpHeaders ## Extra HTTP headers to add to the WebSocket request - pinnedServerCertificate*: seq[uint8] ## An X.509 cert to "pin" TLS connections to (PEM or DER) - trustedRootCertificates*: seq[uint8] ## Set of anchor certs (PEM format) - - channels*: seq[string] ## Optional set of channels to pull from - documentIDs*: seq[string] ## Optional set of document IDs to replicate - pushFilter*: ReplicationFilter ## Optional callback to filter which docs are pushed - pullFilter*: ReplicationFilter ## Optional callback to validate incoming docs - conflictResolver*: ConflictResolver ## Optional conflict-resolver callback - - -#======== LIFECYCLE - - -type - ReplicatorObj {.requiresInit.} = object - handle: CBLReplicator not nil - Replicator* = ref ReplicatorObj not nil - ## A background task that syncs a Database with a remote server or peer. - -proc `=destroy`(r: var ReplicatorObj) = release(r.handle) -proc `=`(dst: var ReplicatorObj; src: ReplicatorObj) {.error.} - - -proc newReplicator*(configuration: ReplicatorConfiguration): Replicator = - ## Creates a replicator with the given configuration. - throw ErrorCode.Unimplemented - -proc configuration*(repl: Replicator): ReplicatorConfiguration = - ## Returns the configuration of an existing replicator. - throw ErrorCode.Unimplemented - -proc resetCheckpoint*(repl: Replicator) = - ## Instructs the replicator to ignore existing checkpoints the next time it - ## runs. This will cause it to scan through all the documents on the remote - ## database, which takes a lot longer, but it can resolve problems with - ## missing documents if the client and server have gotten out of sync - ## somehow. - throw ErrorCode.Unimplemented - -proc start*(repl: Replicator) = - ## Starts a replicator, asynchronously. Does nothing if it's already started. - throw ErrorCode.Unimplemented - -proc stop*(repl: Replicator) = - ## Stops a running replicator, asynchronously. Does nothing if it's not - ## already started. The replicator will call your ChangeListener with an - ## activity level of ``Stopped`` after it stops. Until then, consider it - ## still active. - throw ErrorCode.Unimplemented - -proc setHostReachable*(repl: Replicator; reachable: bool) = - ## Informs the replicator whether it's considered possible to reach the - ## remote host with the current network configuration. The default value is - ## true. This only affects the replicator's behavior while it's in the - ## Offline state: - ## * Setting it to false will cancel any pending retry and prevent future - ## automatic retries. - ## * Setting it back to true will initiate an immediate retry. - throw ErrorCode.Unimplemented - -proc setSuspended*(repl: Replicator; suspended: bool) = - ## Puts the replicator in or out of "suspended" state. The default is false. - ## * Setting suspended=true causes the replicator to disconnect and enter - ## Offline state; it will not attempt to reconnect while it's suspended. - ## * Setting suspended=false causes the replicator to attempt to reconnect, - ## _if_ it was connected when suspended, and is still in Offline state. - throw ErrorCode.Unimplemented - - -#======= STATUS AND PROGRESS - - -type - ActivityLevel* = enum - ## The possible states a replicator can be in during its lifecycle. - Stopped, ## unstarted, finished, or hit a fatal error. - Offline, ## offline, as the remote host is unreachable. - Connecting, ## connecting to the remote host. - Idle, ## inactive, waiting for changes to sync. - Busy ## actively transferring data. - - ReplicatorProgress* = object - ## The current progress status of a Replicator. The `fraction_complete` - ## ranges from 0.0 to 1.0 as replication progresses. The value is very - ## approximate and may bounce around during replication; making it more - ## accurate would require slowing down the replicator and incurring more - ## load on the server. It's fine to use in a progress bar, though. - fractionComplete*: float - documentCount*: uint64 - - ReplicatorStatus* = object - ## A replicator's current status. - activity*: ActivityLevel - progress*: ReplicatorProgress - error*: Error - -proc status*(repl: Replicator): ReplicatorStatus = - ## Returns the replicator's current status. - throw ErrorCode.Unimplemented - -proc pendingDocIDs*(repl: Replicator): HashSet[string] = - ## Indicates which documents have local changes that have not yet been pushed - ## to the server by this replicator. This is of course a snapshot, that will - ## go out of date as the replicator makes progress and/or documents are saved - ## locally. - throw ErrorCode.Unimplemented - -proc isDocumentPending*(repl: Replicator; docID: string): bool = - ## Indicates whether the document with the given ID has local changes that - ## have not yet been pushed to the server by this replicator. - ## - ## This is equivalent to, but faster than, calling ``pendingDocumentIDs`` and - ## checking whether the result contains ``docID``. See that function's - ## documentation for details. - throw ErrorCode.Unimplemented - -type - DocumentFlag = enum deleted, accessRemoved - Direction = enum pulled, pushed - - ReplicatedDocument* = object - ## Information about a document that's been pushed or pulled. - id: string - flags: set[DocumentFlag] - error: Error - - ChangeListener* = proc(replicator: Replicator; status: ReplicatorStatus) - ## A callback that notifies you when the replicator's status changes. - ReplicatedDocumentListener* = proc(replicator: Replicator; - direction: Direction; - documents: seq[ReplicatedDocument]) - ## A callback that notifies you when documents are replicated. - -proc addChangeListener*(repl: Replicator; - listener: ChangeListener): ListenerToken = - ## Adds a listener that will be called when the replicator's status changes. - throw ErrorCode.Unimplemented - -proc addDocumentListener*(repl: Replicator): ListenerToken = - ## Adds a listener that will be called when documents are replicated. - throw ErrorCode.Unimplemented diff --git a/bindings/nim/tests/config.nims b/bindings/nim/tests/config.nims deleted file mode 100644 index 3bb69f82..00000000 --- a/bindings/nim/tests/config.nims +++ /dev/null @@ -1 +0,0 @@ -switch("path", "$projectDir/../src") \ No newline at end of file diff --git a/bindings/nim/tests/test1Fleece.nim b/bindings/nim/tests/test1Fleece.nim deleted file mode 100644 index 2c9587e7..00000000 --- a/bindings/nim/tests/test1Fleece.nim +++ /dev/null @@ -1,206 +0,0 @@ -# Fleece unit tests -# -# Copyright (c) 2020 Couchbase, Inc All rights reserved. -# -# 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 CouchbaseLite/fleece -import unittest - - - -suite "Fleece Accessors": - let JSON = """{"integer": 1234, "string": "Hello, World!", "float": 1234.56, - "true":true, "false": false, "null": null, - "array": [null, false, true, 10, [], {}], - "dict": {"foo": "bar", "frob": -9}}""" - var doc: Fleece - - setup: - doc = parseJSON(JSON) - - test "Parse JSON": - check doc.root.toJSON == """{"array":[null,false,true,10,[],{}],"dict":{"foo":"bar","frob":-9},"false":false,"float":1234.56,"integer":1234,"null":null,"string":"Hello, World!","true":true}""" - - test "Null": - let n = doc["null"] - check n != nil - check n.type == Type.null - check n.asBool == false - - test "Bool": - let t = doc["true"] - check t != nil - check t.type == Type.bool - check not t.isNumber - check t.asBool == true - check t != 1 - - let f = doc["false"] - check f != nil - check f.type == Type.bool - check not f.isNumber - check f.asBool == false - check f != 0 - - test "Int": - check doc.root["integer"].asInt == 1234 - let i = doc["integer"] - check i != nil - check i.type == Type.number - check i.isInt - check not i.isFloat - check i == doc.root["integer"] - check i.asInt == 1234 - check i.asInt(0'i8) == 127'i8 - check i.asFloat == 1234.0 - check i.asString == "" - check i.asString("nope") == "nope" - check i == 1234 - check i == 1234.0f64 - check i != 4321 - - test "Float": - let f = doc["float"] - check f != nil - check f.type == Type.number - check f.isFloat - check not f.isInt - check f.asString == "" - check f.asInt == 1234 - check f.asFloat == 1234.56 - check f.asBool == true - check f == 1234.56 - check f != 1234 - - test "String": - let s = doc["string"] - check s != nil - check s.type == Type.string - check s.asString == "Hello, World!" - check s == "Hello, World!" - check s != 0 - check s != 3.14 - - test "Undefined": - let m = doc["MISSING"] - check m == nil - check m.type == Type.undefined - check m != 0 - - test "Array": - let v = doc["array"] - check v != nil - check v.type == Type.array - let a = v.asArray - check a != nil - check a.len == 6 - check not a.isEmpty - check a[0].type == Type.null - check a[1].type == Type.bool - check a[2].type == Type.bool - check a[3].type == Type.number - check a[4].type == Type.array - check a[5].type == Type.dict - - test "Array iterator": - var i = 0 - let expected = @["null", "false", "true", "10", "[]", "{}"] - for item in doc["array"].asArray: - check $item == expected[i] - i += 1 - check i == 6 - - test "Dict iterator": - var i = 0 - let expectedKeys = @["foo", "frob"] - let expectedVals = @["\"bar\"", "-9"] - for k, v in doc["dict"].asDict.items: - check k == expectedKeys[i] - check $v == expectedVals[i] - i += 1 - check i == 2 - - test "Empty array iterator": - let a = doc["array"][4].asArray - check a != nil - for item in a: - check false - - test "Empty dict iterator": - let d = doc["array"][5].asDict - check d != nil - for item in d: - check false - - test "KeyPath": - var path = keyPath("dict.frob") - check $(path.eval(doc.root)) == "-9" - path = keyPath("array[2]") - check $(path.eval(doc.root)) == "true" - - - -suite "Mutable Fleece": - test "mutable array": - var a = newMutableArray() - check a.len == 0 - check a.isEmpty - check not a.isChanged - a.add(17) - a.add(true) - a.add("howdy") - check a.len == 3 - check $a == "[17,true,\"howdy\"]" - a[1] = false - check $a == "[17,false,\"howdy\"]" - a.delete(0) - check $a == "[false,\"howdy\"]" - a.add(-3.14) - check $a == "[false,\"howdy\",-3.14]" - check a.source == nil - check a.isChanged - - test "mutable dict": - var d = newMutableDict() - check d.len == 0 - check d.isEmpty - check not d.isChanged - d["x"] = 17 - d["y"] = true - d["z"] = "howdy" - check d.len == 3 - check $d == """{"x":17,"y":true,"z":"howdy"}""" - d["y"] = false - check $d == """{"x":17,"y":false,"z":"howdy"}""" - d.delete("x") - check $d == """{"y":false,"z":"howdy"}""" - d["zz"] = -3.14 - check $d == """{"y":false,"z":"howdy","zz":-3.14}""" - check d.source == nil - check d.isChanged - - test "Assign mutable array": - var a = newMutableArray() - a.add(17) - a.add(true) - a.add("howdy") - - var b = newMutableArray() - b.add(false) - - a = b - check $a == "[false]" - check $b == "[false]" diff --git a/bindings/nim/tests/test2Database.nim b/bindings/nim/tests/test2Database.nim deleted file mode 100644 index 0d73fa66..00000000 --- a/bindings/nim/tests/test2Database.nim +++ /dev/null @@ -1,93 +0,0 @@ -# Couchbase Lite unit tests -# -# Copyright (c) 2020 Couchbase, Inc All rights reserved. -# -# 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 CouchbaseLite - -import unittest - -{.experimental: "notnil".} - - -suite "Database": - var db: Database - - setup: - var config = DatabaseConfiguration(directory: "/tmp", flags: {DatabaseFlag.create}) - deleteDatabase("nimtest", config.directory) - db = openDatabase("nimtest", config) - - teardown: - db.close() - - test "Empty db": - check db.name == "nimtest" - check db.path == "/tmp/nimtest.cblite2/" - check db.count == 0 - check db.getDocument("foo") == nil - - test "Create doc": - var newDoc = newDocument("foo") - check newDoc.id == "foo" - check newDoc.revisionID == "" - check newDoc.propertiesAsJSON == "{}" - check newDoc.properties.len == 0 - check db.count == 0 - - newDoc.propertiesAsJSON = """{"language":"nim","rating":9.5}""" - let savedDoc = db.saveDocument(newDoc, FailOnConflict) - check savedDoc.id == "foo" - check savedDoc.revisionID == "1-157a814d5c032e28f674c08f46722e2b07e6d879" - check savedDoc.propertiesAsJSON == """{"language":"nim","rating":9.5}""" - check db.count == 1 - - # Load the doc from the db: - let doc = db.getDocument("foo") - check doc != nil - check doc["rating"] == 9.5 - var ratingKey = dictKey("rating") - check doc[ratingKey] == 9.5 - check doc["language"] == "nim" - check doc["nope"] == nil - - db.deleteDocument(doc) - check db.count == 0 - - test "Save conflict": - var newDoc = newDocument("foo") - db.saveDocument(newDoc, FailOnConflict) - - let conflict = newDocument("foo") - conflict.propertiesAsJSON = """{"oops":true}""" - expect(Error): - db.saveDocument(conflict, FailOnConflict) - - test "Modify doc": - var newDoc = newDocument("foo") - var props = newDoc.properties - props["language"] = "nim" - props["rating"] = 9.5 - var a = newMutableArray() - a.add(123.456) - a.add("hi") - props["array"] = a - - newDoc = db.saveDocument(newDoc).mutableCopy() - newDoc["rating"] = 9.6 - db.saveDocument(newDoc, FailOnConflict) - - check db["foo"].propertiesAsJSON == """{"array":[123.456,"hi"],"language":"nim","rating":9.6}""" diff --git a/bindings/python/BuildPyCBL.py b/bindings/python/BuildPyCBL.py deleted file mode 100755 index 269b658b..00000000 --- a/bindings/python/BuildPyCBL.py +++ /dev/null @@ -1,430 +0,0 @@ -#! /usr/bin/env python3 -# -# BuildPyCBL.py -# -# Copyright (c) 2019 Couchbase, Inc All rights reserved. -# -# 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. -# - - -# Run this to build the PyCBL native glue library, in the current directory -# (Argument handling is at the end of the script) - -import argparse -import os.path -import platform -import shutil -from cffi import FFI - - -# Assume we are running this from bindings/python/CouchbaseLite/ -DEFAULT_SRC_DIR = "../../../" - -# Paths relative to the source root (--srcdir) -CBL_INCLUDE_DIR = "/include" -FLEECE_INCLUDE_DIR = "/vendor/couchbase-lite-core/vendor/fleece/API" - -# CMake settings are defaults, but overrideable on command-line -DEFAULT_LIBRARIES = "cblite z" -DEFAULT_LIBRARY_DIR = DEFAULT_SRC_DIR + "build_cmake/" - -# Extra linker arguments -- platform-specific -DEFAULT_LINK_ARGS = "" -if platform.system() == "Darwin": - DEFAULT_LINK_ARGS = "-rpath @loader_path" # Look for CBL dylib in same dir as bindings lib - - -def BuildLibrary(sourceDir, python_includedir, libdir, libraries, extra_link_args): - # when cross-compiling, use python headers for target rather than build system - include_dirs = [sourceDir+CBL_INCLUDE_DIR, sourceDir+FLEECE_INCLUDE_DIR] - if python_includedir: - include_dirs.insert(0, python_includedir) - - # python 3.5 distutils breaks on Linux with absolute library path, - # so make sure it is relative path - libdir = os.path.relpath(libdir) - - # Copy the CBL library here: - libpath = libdir + "/libcblite" - if platform.system() == "Darwin": - libpath += ".dylib" - else: - libpath += ".so" - shutil.copy(libpath, ".") - - # CFFI stuff -- see https://cffi.readthedocs.io/en/latest/index.html - - # This is passed to the real C compiler and should include the declarations of - # the symbols declared in cdef() - cHeaderSource = r"""#include """ - - ffibuilder = FFI() - ffibuilder.cdef(CDeclarations()) - ffibuilder.set_source( - "_PyCBL", # Module name - cHeaderSource, - libraries=libraries, - include_dirs=include_dirs, - library_dirs=["."], - extra_link_args=extra_link_args) - ffibuilder.compile(verbose=True) - - os.remove("_PyCBL.c") - os.remove("_PyCBL.o") - - -def CDeclarations(): - return r""" -// Declarations that are shared between Python and C -// (Careful, this supports only a subset of C syntax) -// Needs to be updated whenever public C API changes! - -void free(void *); -typedef int64_t CBLTimestamp; - -//////// Fleece (slices): -typedef struct {const void *buf; size_t size;} FLSlice; -typedef struct {const void *buf; size_t size;} FLSliceResult; -typedef FLSlice FLHeapSlice; -typedef FLSlice FLString; -typedef FLSliceResult FLStringResult; - -bool FLSlice_Equal(FLSlice a, FLSlice b); -int FLSlice_Compare(FLSlice, FLSlice); -FLSliceResult FLSliceResult_Retain(FLSliceResult); -void FLSliceResult_Release(FLSliceResult); -FLSliceResult FLSlice_Copy(FLSlice); - -//////// Fleece (values): -typedef ... * FLValue; ///< A reference to a value of any type. -typedef ... * FLArray; ///< A reference to an array value. -typedef ... * FLDict; ///< A reference to a dictionary (map) value. -typedef ... * FLMutableArray; ///< A reference to a mutable array. -typedef ... * FLMutableDict; ///< A reference to a mutable dictionary. -typedef ... * FLSlot; -typedef unsigned FLError; - -typedef enum { - kFLUndefined = -1, ///< Type of a NULL pointer, i.e. no such value, like JSON `undefined`. Also the type of a value created by FLEncoder_WriteUndefined(). - kFLNull = 0, ///< Equivalent to a JSON 'null' - kFLBoolean, ///< A `true` or `false` value - kFLNumber, ///< A numeric value, either integer or floating-point - kFLString, ///< A string - kFLData, ///< Binary data (no JSON equivalent) - kFLArray, ///< An array of values - kFLDict ///< A mapping of strings to values -} FLValueType; - -FLValueType FLValue_GetType(FLValue); -bool FLValue_IsInteger(FLValue); -bool FLValue_IsUnsigned(FLValue); -bool FLValue_IsDouble(FLValue); -bool FLValue_AsBool(FLValue); -int64_t FLValue_AsInt(FLValue); -uint64_t FLValue_AsUnsigned(FLValue); -float FLValue_AsFloat(FLValue); -double FLValue_AsDouble(FLValue); -FLString FLValue_AsString(FLValue); -FLArray FLValue_AsArray(FLValue); -FLDict FLValue_AsDict(FLValue); - -typedef struct { ...; } FLArrayIterator; -uint32_t FLArray_Count(FLArray); -FLValue FLArray_Get(FLArray, uint32_t index); -void FLArrayIterator_Begin(FLArray, FLArrayIterator*); -FLValue FLArrayIterator_GetValue(const FLArrayIterator*); -FLValue FLArrayIterator_GetValueAt(const FLArrayIterator*, uint32_t offset); -uint32_t FLArrayIterator_GetCount(const FLArrayIterator*); -bool FLArrayIterator_Next(FLArrayIterator*); - -typedef struct { ...; } FLDictIterator; -uint32_t FLDict_Count(FLDict); -FLValue FLDict_Get(FLDict, FLSlice keyString); -void FLDictIterator_Begin(FLDict, FLDictIterator*); -FLString FLDictIterator_GetKeyString(const FLDictIterator*); -FLValue FLDictIterator_GetValue(const FLDictIterator*); -uint32_t FLDictIterator_GetCount(const FLDictIterator* ); -bool FLDictIterator_Next(FLDictIterator*); -void FLDictIterator_End(FLDictIterator*); - - -//////// CBLBase.h -typedef uint32_t CBLErrorDomain; -typedef uint8_t CBLLogDomain; -typedef uint8_t CBLLogLevel; - -typedef struct { - CBLErrorDomain domain; ///< Domain of errors; a namespace for the `code`. - int32_t code; ///< Error code, specific to the domain. 0 always means no error. - int32_t internal_info; -} CBLError; -char* CBLError_Message(const CBLError*); -FLSliceResult CBLError_Message_s(const CBLError*); - -void CBL_Log(CBLLogDomain domain, CBLLogLevel level, const char *format, ...); -void CBL_Log_s(CBLLogDomain domain, CBLLogLevel level, FLSlice message); -CBLLogLevel CBLLog_ConsoleLevel(void); -void CBLLog_SetConsoleLevel(CBLLogLevel); -bool CBLLog_WillLogToConsole(CBLLogDomain domain, CBLLogLevel level); - -typedef ... CBLRefCounted; -CBLRefCounted* CBL_Retain(void*); -void CBL_Release(void*); - -typedef ... CBLBlob; -typedef ... CBLDatabase; -typedef ... CBLDocument; -typedef ... CBLQuery; -typedef ... CBLResultSet; -typedef ... CBLReplicator; -typedef ... CBLListenerToken; - -typedef enum { - kCBLDatabase_Create = 1, ///< Create the file if it doesn't exist - kCBLDatabase_ReadOnly = 2, ///< Open file read-only - kCBLDatabase_NoUpgrade = 4, ///< Disable upgrading an older-version database -} CBLDatabaseFlags; - -typedef struct { - const char *directory; - CBLDatabaseFlags flags; - ...; -} CBLDatabaseConfiguration; - -typedef struct { - FLString directory; - CBLDatabaseFlags flags; - ...; -} CBLDatabaseConfiguration_s; - -void CBLListener_Remove(CBLListenerToken*); - - -//////// CBLBlob.h -bool CBL_IsBlob(FLDict); -const CBLBlob* CBLBlob_Get(FLDict blobDict); -uint64_t CBLBlob_Length(const CBLBlob*); -const char* CBLBlob_Digest(const CBLBlob*); -const char* CBLBlob_ContentType(const CBLBlob*); -FLDict CBLBlob_Properties(const CBLBlob*); -FLSliceResult CBLBlob_LoadContent(const CBLBlob*, CBLError *outError); - -typedef ... CBLBlobReadStream; -CBLBlobReadStream* CBLBlob_OpenContentStream(const CBLBlob*, CBLError *outError); -int CBLBlobReader_Read(CBLBlobReadStream* stream, void *dst, size_t maxLength, CBLError *outError); -void CBLBlobReader_Close(CBLBlobReadStream*); - -CBLBlob* CBLBlob_CreateWithData(const char *contentType, FLSlice contents); -CBLBlob* CBLBlob_CreateWithData_s(FLString contentType, FLSlice contents); - -typedef ... CBLBlobWriteStream; -CBLBlobWriteStream* CBLBlobWriter_New(CBLDatabase *db, CBLError *outError); -void CBLBlobWriter_Close(CBLBlobWriteStream*); -bool CBLBlobWriter_Write(CBLBlobWriteStream* writer, const void *data, size_t length, CBLError *outError); -CBLBlob* CBLBlob_CreateWithStream(const char *contentType, CBLBlobWriteStream* writer); -CBLBlob* CBLBlob_CreateWithStream_s(FLString contentType, CBLBlobWriteStream* writer); - -void FLSlot_SetBlob(FLSlot slot, CBLBlob* blob); - - -//////// CBLDatabase.h -bool CBL_DatabaseExists(const char* name, const char *inDirectory); -bool CBL_DatabaseExists_s(FLString name, FLString inDirectory); -bool CBL_CopyDatabase(const char* fromPath, - const char* toName, - const CBLDatabaseConfiguration* config, - CBLError*); -bool CBL_CopyDatabase_s(FLString fromPath, - FLString toName, - const CBLDatabaseConfiguration_s* config, - CBLError*); -bool CBL_DeleteDatabase(const char *name, - const char *inDirectory, - CBLError*); -CBLDatabase* CBLDatabase_Open(const char *name, - const CBLDatabaseConfiguration* config, - CBLError* error); -bool CBLDatabase_Close(CBLDatabase*, CBLError*); -bool CBLDatabase_Delete(CBLDatabase*, CBLError*); -bool CBLDatabase_Compact(CBLDatabase*, CBLError*); -bool CBLDatabase_BeginBatch(CBLDatabase*, CBLError*); -bool CBLDatabase_EndBatch(CBLDatabase*, CBLError*); -const char* CBLDatabase_Name(const CBLDatabase*); -const char* CBLDatabase_Path(const CBLDatabase*); -uint64_t CBLDatabase_Count(const CBLDatabase*); -CBLDatabaseConfiguration CBLDatabase_Config(const CBLDatabase*); - -typedef void (*CBLDatabaseChangeListener)(void *context, - const CBLDatabase* db, - unsigned numDocs, - const char **docIDs); -extern "Python" void databaseListenerCallback(void *context, const CBLDatabase* db, - unsigned numDocs, const char **docIDs); -CBLListenerToken* CBLDatabase_AddChangeListener(const CBLDatabase* db, - CBLDatabaseChangeListener listener, - void *context); - - -//////// CBLDocument.h -typedef uint8_t CBLConcurrencyControl; -const CBLDocument* CBLDatabase_GetDocument(const CBLDatabase* database, - const char* docID); -const CBLDocument* CBLDatabase_GetDocument_s(const CBLDatabase* database, - FLString docID); -const CBLDocument* CBLDatabase_SaveDocument(CBLDatabase* db, - CBLDocument* doc, - CBLConcurrencyControl concurrency, - CBLError* error); -bool CBLDocument_Delete(const CBLDocument* document, - CBLConcurrencyControl concurrency, - CBLError* error); -bool CBLDocument_Purge(const CBLDocument* document, - CBLError* error); -bool CBLDatabase_PurgeDocumentByID(CBLDatabase* database, - const char* docID, - CBLError* error); -bool CBLDatabase_PurgeDocumentByID_s(CBLDatabase* database, - FLString docID, - CBLError* error); -CBLTimestamp CBLDatabase_GetDocumentExpiration(CBLDatabase* db, - const char *docID, - CBLError* error); -CBLTimestamp CBLDatabase_GetDocumentExpiration_s(CBLDatabase* db, - FLSlice docID, - CBLError* error); -bool CBLDatabase_SetDocumentExpiration(CBLDatabase* db, - const char *docID, - CBLTimestamp expiration, - CBLError* error); -bool CBLDatabase_SetDocumentExpiration_s(CBLDatabase* db, - FLSlice docID, - CBLTimestamp expiration, - CBLError* error); -CBLDocument* CBLDatabase_GetMutableDocument(CBLDatabase* database, - const char* docID); -CBLDocument* CBLDatabase_GetMutableDocument_s(CBLDatabase* database, - FLString docID); -CBLDocument* CBLDocument_New(const char *docID); -CBLDocument* CBLDocument_New_s(FLString docID); -CBLDocument* CBLDocument_MutableCopy(const CBLDocument* original); -const char* CBLDocument_ID(const CBLDocument*); -uint64_t CBLDocument_Sequence(const CBLDocument*); -FLDict CBLDocument_Properties(const CBLDocument*); -FLMutableDict CBLDocument_MutableProperties(CBLDocument*); -char* CBLDocument_PropertiesAsJSON(const CBLDocument*); -bool CBLDocument_SetPropertiesAsJSON(CBLDocument*, const char *json, CBLError*); -bool CBLDocument_SetPropertiesAsJSON_s(CBLDocument*, FLSlice json, CBLError*); - -typedef void (*CBLDocumentChangeListener)(void *context, - const CBLDatabase* db, - const char *docID); -CBLListenerToken* CBLDatabase_AddDocumentChangeListener(const CBLDatabase* db, - const char* docID, - CBLDocumentChangeListener listener, - void *context); -extern "Python" void documentListenerCallback(void *context, const CBLDatabase*, const char *docID); - -//////// CBLQuery.h -typedef enum { - kCBLJSONLanguage, - kCBLN1QLLanguage -} CBLQueryLanguage; -CBLQuery* CBLQuery_New(const CBLDatabase* db, - CBLQueryLanguage language, - const char *queryString, - int *outErrorPos, - CBLError* error); -CBLQuery* CBLQuery_New_s(const CBLDatabase* db, - CBLQueryLanguage language, - FLString queryString, - int *outErrorPos, - CBLError* error); -FLDict CBLQuery_Parameters(CBLQuery* query); -void CBLQuery_SetParameters(CBLQuery* query, - FLDict parameters); -void CBLQuery_SetParametersAsJSON(CBLQuery* query, const char* json); -bool CBLQuery_SetParametersAsJSON_s(CBLQuery* query, FLString json); -CBLResultSet* CBLQuery_Execute(CBLQuery*, CBLError*); -FLSliceResult CBLQuery_Explain(CBLQuery*); -unsigned CBLQuery_ColumnCount(CBLQuery*); -FLSlice CBLQuery_ColumnName(CBLQuery*, - unsigned columnIndex); -bool CBLResultSet_Next(CBLResultSet*); -FLValue CBLResultSet_ValueAtIndex(CBLResultSet*, unsigned index); -FLValue CBLResultSet_ValueForKey(CBLResultSet*, const char* key); -FLValue CBLResultSet_ValueForKey_s(const CBLResultSet*, FLString key); -FLArray CBLResultSet_RowArray(const CBLResultSet*); -FLDict CBLResultSet_RowDict(const CBLResultSet*); -CBLQuery* CBLResultSet_GetQuery(const CBLResultSet *rs); - -typedef void (*CBLQueryChangeListener)(void *context, - CBLQuery* query); -extern "Python" void queryListenerCallback(void *context, const CBLQuery *query); -CBLListenerToken* CBLQuery_AddChangeListener(CBLQuery* query, - CBLQueryChangeListener listener, - void *context); - -typedef enum { - kCBLValueIndex, ///< An index that stores property or expression values - kCBLFullTextIndex ///< An index of strings, that enables searching for words with `MATCH` -} CBLIndexType; - -typedef struct { - CBLIndexType type; - const char* keyExpressionsJSON; - bool ignoreAccents; - const char* language; -} CBLIndexSpec; - -typedef struct { - CBLIndexType type; - FLString keyExpressionsJSON; - bool ignoreAccents; - FLString language; -} CBLIndexSpec_s; - -bool CBLDatabase_CreateIndex(CBLDatabase *db, - const char* name, - CBLIndexSpec, - CBLError *outError); -bool CBLDatabase_CreateIndex_s(CBLDatabase *db, - FLString name, - CBLIndexSpec_s, - CBLError *outError); -bool CBLDatabase_DeleteIndex(CBLDatabase *db, - const char *name, - CBLError *outError); -FLMutableArray CBLDatabase_IndexNames(CBLDatabase *db); -""" - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="build Couchbase Lite Python bindings") - parser.add_argument('--srcdir', default=DEFAULT_SRC_DIR, - help="Source root directory") - parser.add_argument('--python_includedir', default='', - help="Directory containing python headers (specify for cross-compiling)") - parser.add_argument('--libdir', default=DEFAULT_LIBRARY_DIR, - help="Directory containing CBL libraries") - parser.add_argument('--libs', default=DEFAULT_LIBRARIES, - help="Library names") - parser.add_argument('--link_flags', default=DEFAULT_LINK_ARGS, - help="Linker flags") - args = parser.parse_args() - - linkFlags = None - if args.link_flags != None: - linkFlags = args.link_flags.split() - - BuildLibrary(args.srcdir, args.python_includedir, args.libdir, args.libs.split(), linkFlags) diff --git a/bindings/python/CouchbaseLite/Blob.py b/bindings/python/CouchbaseLite/Blob.py deleted file mode 100644 index 1392c029..00000000 --- a/bindings/python/CouchbaseLite/Blob.py +++ /dev/null @@ -1,49 +0,0 @@ -from ._PyCBL import ffi, lib -from .Collections import * -from .common import * - -class Blob (object): - def __init__(self, data, *, contentType =None, fdict =None): - if fdict != None: - super.__init__(lib.CBLBlob_Get(fdict), "Dict is not a Blob") - else: - super.__init__(lib.CBLBlob_CreateWithData(contentType, asSlice(data)), - "Failed to create Blob") - - @property - def digest(self): - return pystr(lib.CBLBlob_Digest(self._ref)) - - @property - def length(self): - return lib.CBLBlob_Length(self._ref) - - @property - def contentType(self): - return pystr(lib.CBLBlob_ContentType(self._ref)) - - @property - def data(self): - if "_data" in self.__dict__: - return self._data - elif self.digest != None: - sliceResult = lib.CBLBlob_LoadContent(self._ref, gError) - # OPT: This copies the bytes - result = sliceResultToBytes(sliceResult) - lib.FLSliceResult_Release(sliceResult) - return result - else: - return None - - def __repr__(self): - r = "Blob[" - if self.contentType != None: - r += self.contentType - if self.length != None: - if self.contentType != None: - r += ", " - r += self.length + " bytes" - return r + "]" - - def _jsonEncodable(self): - return decodeFleeceDict( lib.CBLBlob_Properties(self._ref), depth=99 ) diff --git a/bindings/python/CouchbaseLite/Collections.py b/bindings/python/CouchbaseLite/Collections.py deleted file mode 100644 index f32137ce..00000000 --- a/bindings/python/CouchbaseLite/Collections.py +++ /dev/null @@ -1,208 +0,0 @@ -from ._PyCBL import ffi, lib -from .common import * -from .Blob import Blob -from collections.abc import Sequence, Mapping -from functools import total_ordering -import json - - -FLArrayType = ffi.typeof("struct $$FLArray *") -FLDictType = ffi.typeof("struct $$FLDict *") - - -#### FLEECE DECODING: - - -# Most general function, accepts params of type FLValue, FLDict or FLArray. -def decodeFleece(f, *, depth =1, mutable =False): - ffitype = ffi.typeof(f) - if ffitype == FLDictType: - return decodeFleeceDict(f, depth=depth, mutable=mutable) - elif ffitype == FLArrayType: - return decodeFleeceArray(f, depth=depth, mutable=mutable) - else: - return decodeFleeceValue(f, depth=depth, mutable=mutable) - -# Decodes an FLValue (which may of course turn out to be an FLArray or FLDict) -def decodeFleeceValue(f, *, depth =1, mutable =False): - typ = lib.FLValue_GetType(f) - if typ == lib.kFLString: - return sliceToString(lib.FLValue_AsString(f)) - elif typ == lib.kFLDict: - return decodeFleeceDict(ffi.cast(FLDictType, f), depth=depth, mutable=mutable) - elif typ == lib.kFLArray: - return decodeFleeceArray(ffi.cast(FLArrayType, f), depth=depth, mutable=mutable) - elif typ == lib.kFLNumber: - if lib.FLValue_IsInteger(f): - return lib.FLValue_AsInt(f) - elif lib.FLValue_IsDouble(f): - return lib.FLValue_AsDouble(f) - else: - return lib.FLValue_AsFloat(f) - elif typ == lib.kFLBoolean: - return not not lib.FLValue_AsBool(f) - elif typ == lib.kFLNull: - return None # ??? - else: - assert(typ == lib.kFLUndefined) - return None - -# Decodes an FLArray -def decodeFleeceArray(farray, *, depth =1, mutable =False): - if depth <= 0: - if mutable: - return MutableArray(fleece=farray) - else: - return Array(fleece=farray) - result = [] - n = lib.FLArray_Count(farray) - for i in range(n): - value = lib.FLArray_Get(farray, i) - result.append(decodeFleeceValue(value, depth=depth-1, mutable=mutable)) - return result - -# Decodes an FLDict -def decodeFleeceDict(fdict, *, depth =1, mutable =False): - if lib.CBL_IsBlob(fdict): - return Blob(None, fdict=fdict) - elif depth <= 0: - if mutable: - return MutableDictionary(fleece=fdict) - else: - return Dictionary(fleece=fdict) - else: - result = {} - i = ffi.new("FLDictIterator*") - lib.FLDictIterator_Begin(fdict, i) - while True: - value = lib.FLDictIterator_GetValue(i) - if not value: - break - key = sliceToString( lib.FLDictIterator_GetKeyString(i) ) - result[key] = decodeFleeceValue(value, depth=depth-1, mutable=mutable) - lib.FLDictIterator_Next(i) - return result - - -### Array class - - -@total_ordering -class Array (Sequence): - "A Couchbase Lite array, decoded from a Document or Query. Behaves like a regular Python sequence." - - def __init__(self, *, fleece=None): - "Constructor: takes an FLArray" - if fleece != None: - self._flArray = fleece - else: - self._pyList = [] - - def __len__(self): - if not "_pyList" in self.__dict__: - return lib.FLArray_Count(self._flArray) - return len(self._pyList) - - @property - def _toList(self): - if not "_pyList" in self.__dict__: - # Convert Fleece array to Python list: - self._pyList = decodeFleeceArray(self._flArray, depth=1) - del self._flArray - print ("Converted Array to list") - return self._pyList - - def __getitem__(self, i): - return self._toList[i] - - def __repr__(self): - if not "_pyList" in self.__dict__: - # Don't convert in place; just return the converted form's representation - return decodeFleeceArray(self._flArray, depth=999).__repr__() - return self._pyList.__repr__() - - def __eq__(self, other): - return self._toList == other - - def __gt__(self, other): - return self._toList > other - - def _jsonEncodable(self): - return self._toList - - -class MutableArray (Array): - def __setitem__(self, i, value): - self._toList.__setitem__(i, value) - - def __delitem__(self, i): - self._toList.__deltem__(i) - - def insert(self, i, value): - self._toList.insert(i, value) - - -### Dictionary class - - -class Dictionary (Mapping): - "A Couchbase Lite dictionary, decoded from a Document or Query. Behaves like a regular Python mapping." - def __init__(self, *, fleece=None): - if fleece != None: - self._flDict = fleece - else: - self._pyDict = {} - - def __len__(self): - if not "_pyMap" in self.__dict__: - return lib.FLDict_Count(self._flDict) - return len(self._pyMap) - - @property - def _toDict(self): - if not "_pyMap" in self.__dict__: - # Convert Fleece dict to Python mapping: - self._pyMap = decodeFleeceDict(self._flDict) - del self._flDict - return self._pyMap - - def __getitem__(self, key): - return self._toDict.__getitem__(key) - - def __iter__(self): - return self._toDict.__iter__() - - def __repr__(self): - if not "_pyMap" in self.__dict__: - # Don't convert in place; just return the converted form's representation - return decodeFleeceDict(self._flDict, depth=999).__repr__() - return self._toDict.__repr__() - - def __eq__(self, other): - return self._toDict == other - def __ne__(self, other): - return not self.__eq__(other) - - def _jsonEncodable(self): - return self._toDict - - -class MutableDictionary (Dictionary): - def __setitem__(self, key, value): - self._toDict.__setitem__(key, value) - - def __delitem__(self, key): - self._toDict.__deltem__(key) - - -### JSON Encoder - - -def encodeJSON(root, sortKeys =False): - # Custom JSON encoding for Array, Dictionary, Blob objects - def _defaultEncodeJSON(o): - try: - return o._jsonEncodable() - except AttributeError: - raise TypeError("Couchbase Lite documents cannot contain objects of type " + str(type(o))) - return json.dumps(root, default=_defaultEncodeJSON, sort_keys=sortKeys, allow_nan=False) diff --git a/bindings/python/CouchbaseLite/Database.py b/bindings/python/CouchbaseLite/Database.py deleted file mode 100644 index 24049e90..00000000 --- a/bindings/python/CouchbaseLite/Database.py +++ /dev/null @@ -1,189 +0,0 @@ -# Database.py -# -# Copyright (c) 2019 Couchbase, Inc All rights reserved. -# -# 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 datetime -import math - -from ._PyCBL import ffi, lib -from .common import * -from .Document import * - -class DatabaseConfiguration: - def __init__(self, directory, create = True, readOnly = False, noUpgrade = False): - self.directory = directory - self._flags = 0 - if create: - self._flags |= lib.kCBLDatabase_Create - if readOnly: - self._flags |= lib.kCBLDatabase_ReadOnly - if noUpgrade: - self._flags |= lib.kCBLDatabase_NoUpgrade - - def _cblConfig(self): - self._cblDir = cstr(self.directory) # to keep string from being GC'd - return ffi.new("CBLDatabaseConfiguration*", [self._cblDir, self._flags]) - - def __repr__(self): - return "DatabaseConfiguration['" + self.directory + "']" - - -class Database (CBLObject): - def __init__(self, name, config =None): - if config != None: - config = config._cblConfig() - self.name = name - self.listeners = set() - CBLObject.__init__(self, lib.CBLDatabase_Open(cstr(name), config, gError), - "Couldn't open database", gError) - - def __repr__(self): - return "Database['" + self.name + "']" - - def close(self): - if not lib.CBLDatabase_Close(self._ref, gError): - print ("WARNING: Database.close() failed") - - def delete(self): - if not lib.CBLDatabase_Delete(self._ref, gError): - raise CBLException("Couldn't delete database", gError) - - @staticmethod - def deleteFile(name, dir): - if lib.CBL_DeleteDatabase(cstr(name), cstr(dir), gError): - return True - elif gError.code == 0: - return False - else: - raise CBLException("Couldn't delete database file", gError) - - def compact(self): - if not lib.CBLDatabase_Compact(self._ref, gError): - raise CBLException("Couldn't compact database", gError) - - # Attributes: - - def getPath(self): - return pystr(lib.CBLDatabase_Path(self._ref)) - path = property(getPath) - - @property - def config(self): - c_config = lib.CBLDatabase_Config(self._ref) - dir = pystr(c_config.directory) - return DatabaseConfiguration(dir) - - @property - def count(self): - return lib.CBLDatabase_Count(self._ref) - - # Documents: - - def getDocument(self, id): - return Document._get(self, id) - - def getMutableDocument(self, id): - return MutableDocument._get(self, id) - - def saveDocument(self, doc, concurrency = FailOnConflict): - doc._prepareToSave() - savedDocRef = lib.CBLDatabase_SaveDocument(self._ref, doc._ref, concurrency, gError) - if not savedDocRef: - raise CBLException("Couldn't save document", gError) - savedDoc = Document(doc.id) - savedDoc.database = self - savedDoc._ref = savedDocRef - return savedDoc - - def deleteDocument(self, id): - if not lib.CBLDatabase_DeleteDocument(self._ref, cstr(id), gError): - raise CBLException("Couldn't delete document", gError) - - def purgeDocument(self, id): - if not lib.CBLDatabase_PurgeDocument(self._ref, cstr(id), gError): - raise CBLException("Couldn't purge document", gError) - - def __getitem__(self, id): - return self.getMutableDocument(id) - - def __setitem__(self, id, doc): - if id != doc.id: - raise CBLException("key does not match document ID") - self.saveDocument(doc) - - def __delitem__(self, id): - self.deleteDocument(id) - - # Batch operations: (`with db: ...`) - - def __enter__(self): - if not lib.CBLDatabase_BeginBatch(self._ref, gError): - raise CBLException("Couldn't begin a batch operation", gError) - - def __exit__(self, exc_type, exc_value, traceback): - if not lib.CBLDatabase_EndBatch(self._ref, gError) and not exc_type: - raise CBLException("Couldn't commit a batch operation", gError) - - # Expiration: - - def getDocumentExpiration(self, id): - exp = lib.CBLDatabase_GetDocumentExpiration(self._ref, id, gError) - if exp > 0: - return datetime.fromtimestamp(exp) - elif exp == 0: - return None - else: - raise CBLException("Couldn't get document's expiration", gError) - - def setDocumentExpiration(self, id, expDateTime): - timestamp = 0 - if expDateTime != None: - timestamp = math.ceil(expDateTime.timestamp) - if not lib.CBLDatabase_SetDocumentExpiration(self._ref, id, timestamp, gError): - raise CBLException("Couldn't set document's expiration", gError) - - - # Listeners: - - def addListener(self, listener): - handle = ffi.new_handle(listener) - self.listeners.add(handle) - c_token = lib.CBLDatabase_AddChangeListener(self._ref, lib.databaseListenerCallback, handle) - return ListenerToken(self, handle, c_token) - - def addDocumentListener(self, docID, listener): - handle = ffi.new_handle(listener) - self.listeners.add(handle) - c_token = lib.CBLDatabase_AddDocumentChangeListener(self._ref, docID, - lib.databaseListenerCallback, handle) - return ListenerToken(self, handle, c_token) - - def removeListener(self, token): - token.remove() - - -@ffi.def_extern() -def databaseListenerCallback(context, db, numDocs, c_docIDs): - docIDs = [] - for i in range(numDocs): - docIDs.append(pystr(c_docIDs[i])) - listener = ffi.from_handle(context) - listener(docIDs) - -@ffi.def_extern() -def documentListenerCallback(context, db, docID): - listener = ffi.from_handle(context) - listener(pystr(docID)) diff --git a/bindings/python/CouchbaseLite/Document.py b/bindings/python/CouchbaseLite/Document.py deleted file mode 100644 index 57848587..00000000 --- a/bindings/python/CouchbaseLite/Document.py +++ /dev/null @@ -1,139 +0,0 @@ -# Document.py -# -# Copyright (c) 2019 Couchbase, Inc All rights reserved. -# -# 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. -# -from ._PyCBL import ffi, lib -from .common import * -from .Collections import * -import json - -# Concurrency control: -LastWriteWins = 0 -FailOnConflict = 1 - -class Document (CBLObject): - def __init__(self, id): - self.id = id - self._ref = None - - def __repr__(self): - return self.__class__.__name__ + "['" + self.id + "']" - - @staticmethod - def _get(database, id): - ref = lib.CBLDatabase_GetDocument(database._ref, cstr(id)) - if not ref: - return None - doc = Document(id) - doc.database = database - doc._ref = ref - return doc - - def delete(self, concurrency = LastWriteWins): - assert(self._ref) - if not lib.CBLDocument_Delete(self._ref, concurrency, gError): - raise CBLException("Couldn't delete document", gError) - - def purge(self): - assert(self._ref) - if not lib.CBLDocument_Purge(self._ref, gError): - raise CBLException("Couldn't purge document", gError) - - def mutableCopy(self): - mdoc = MutableDocument(self.id) - mdoc.database = self.database - mdoc._ref = lib.CBLDocument_MutableCopy(self._ref) - return mdoc - - @property - def sequence(self): - if not self._ref: - return 0 - return lib.CBLDocument_Sequence(self._ref) - - def getProperties(self): - if not "_properties" in self.__dict__: - if self._ref: - fleeceProps = lib.CBLDocument_Properties(self._ref) - self._properties = decodeFleeceDict(fleeceProps, mutable=self.isMutable) - else: - self._properties = {} - return self._properties - properties = property(getProperties) - - @property - def JSON(self): - return pystr(lib.CBLDocument_PropertiesAsJSON(self._ref)) - - def get(self, key, dflt = None): - return self.properties.get(key, dflt) - def __getitem__(self, key): - return self.properties[key] - def __contains__(self, key): - return key in self.properties - - def addListener(self, listener): - self.database.addDocumentListener(listener) - - @property - def isMutable(self): - return False - - -class MutableDocument (Document): - def __init__(self, id): - Document.__init__(self, id) - - @staticmethod - def _get(database, id): - ref = lib.CBLDatabase_GetMutableDocument(database._ref, cstr(id)) - if not ref: - return None - doc = MutableDocument(id) - doc.database = database - doc._ref = ref - return doc - - @property - def JSON(self): - if "_properties" in self.__dict__: - return encodeJSON(self._properties) - else: - return pystr(lib.CBLDocument_PropertiesAsJSON(self._ref)) - - def setProperties(self, props): - self._properties = props - properties = property(Document.getProperties, setProperties) - - def __setitem__(self, key, value): - self.properties[key] = value - def __delitem__(self, key): - del self.properties[key] - - # Called from Database.saveDocument - def _prepareToSave(self): - if not self._ref: - self._ref = lib.CBLDocument_New(cstr(self.id)) - if "_properties" in self.__dict__: - jsonStr = encodeJSON(self._properties) - if not lib.CBLDocument_SetPropertiesAsJSON(self._ref, cstr(jsonStr), gError): - raise CBLException("Couldn't store properties", gError) - - def save(self, concurrency = FailOnConflict): - return self.database.saveDocument(self, concurrency) - - @property - def isMutable(self): - return True diff --git a/bindings/python/CouchbaseLite/Query.py b/bindings/python/CouchbaseLite/Query.py deleted file mode 100644 index cc7f2e23..00000000 --- a/bindings/python/CouchbaseLite/Query.py +++ /dev/null @@ -1,166 +0,0 @@ -# Query.py -# -# Copyright (c) 2019 Couchbase, Inc All rights reserved. -# -# 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. -# -from ._PyCBL import ffi, lib -from .common import * -from .Collections import * -import json - -JSONLanguage = 0 -N1QLLanguage = 1 - -class Query (CBLObject): - - def __init__(self, database, queryString, language = N1QLLanguage): - errorPos = ffi.new("int*") - CBLObject.__init__(self, - lib.CBLQuery_New(database._ref, language, cstr(queryString), - errorPos, gError), - "Couldn't create query", gError) - self.database = database - self.columnCount = lib.CBLQuery_ColumnCount(self._ref) - self.sourceCode = queryString - self.listeners = set() - - def __repr__(self): - return self.__class__.__name__ + "['" + self.sourceCode + "']" - - @property - def explanation(self): - return sliceToString(lib.CBLQuery_Explain(self._ref)) - - @property - def columnNames(self): - if not "_columns" in self.__dict__: - cols = [] - for i in range(self.columnCount): - name = sliceToString( lib.CBLQuery_ColumnName(self._ref, i) ) - cols.append(name) - self._columns = cols - return self._columns - - def setParameters(self, params): - jsonStr = encodeJSON(params) - lib.CBLQuery_SetParametersAsJSON(self._ref, cstr(jsonStr)) - - def execute(self): - """Executes the query and returns a Generator of QueryResult objects.""" - results = lib.CBLQuery_Execute(self._ref, gError) - if not results: - raise CBLException("Query failed", gError) - try: - lastResult = None - while lib.CBLResultSet_Next(results): - if lastResult: - lastResult.invalidate() - lastResult = QueryResult(self, results) - yield lastResult - finally: - lib.CBL_Release(results) - - # Listeners: - - def addListener(self, listener): - handle = ffi.new_handle(listener) - self.listeners.add(handle) - c_token = lib.CBLQuery_AddChangeListener(self._ref, lib.queryListenerCallback, handle) - return ListenerToken(self, handle, c_token) - - def removeListener(self, token): - token.remove() - - -class JSONQuery (Query): - def __init__(self, database, jsonQuery): - if not isinstance(jsonQuery, str): - jsonQuery = encodeJSON(jsonQuery) - Query.__init__(self, database, jsonQuery, JSONLanguage) - - -class N1QLQuery (Query): - def __init__(self, database, n1ql): - Query.__init__(self, database, n1ql, N1QLLanguage) - - -class QueryResult (object): - """A container representing a query result. It can be indexed using either - integers (to access columns in the order they were declared in the query) - or strings (to access columns by name.)""" - def __init__(self, query, results): - self.query = query - self._ref = results - - def __repr__(self): - if self._ref == None: - return "QueryResult[invalidated]" - return "QueryResult" + encodeJSON(self.asDictionary()) - - def invalidate(self): - self._ref = None - self.query = None - - def __len__(self): - return self.query.columnCount - - def __getitem__(self, key): - if self._ref == None: - raise CBLException("Accessing a non-current query result row") - if isinstance(key, int): - if key < 0 or key >= self.query.columnCount: - raise IndexError("Column index out of range") - item = lib.CBLResultSet_ValueAtIndex(self._ref, key) - elif isinstance(key, str): - item = lib.CBLResultSet_ValueForKey(self._ref, key) - if item == None: - raise KeyError("No such column in Query") - else: - # TODO: Handle slices - raise KeyError("invalid query result key") - return decodeFleece(item) - - def __contains__(self, key): - if self._ref == None: - raise CBLException("Accessing a non-current query result row") - if isinstance(key, int): - if key < 0 or key >= self.query.columnCount: - return False - return (lib.CBLResultSet_ValueAtIndex(self._ref, key) != None) - elif isinstance(key, str): - return (lib.CBLResultSet_ValueForKey(self._ref, key) != None) - else: - return False - - def asArray(self): - result = [] - for i in range(0, self.query.columnCount): - result.append(self[i]) - return result - - def asDictionary(self): - result = {} - keys = self.query.columnNames - for i in range(0, self.query.columnCount): - item = lib.CBLResultSet_ValueAtIndex(self._ref, i) - if lib.FLValue_GetType(item) != lib.kFLUndefined: - result[keys[i]] = decodeFleece(item) - return result - - - -@ffi.def_extern() -def queryListenerCallback(context, query): - listener = ffi.from_handle(context) - listener() diff --git a/bindings/python/CouchbaseLite/__init__.py b/bindings/python/CouchbaseLite/__init__.py deleted file mode 100644 index 4a41f520..00000000 --- a/bindings/python/CouchbaseLite/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# placeholder file, to mark this directory as a Python package diff --git a/bindings/python/CouchbaseLite/common.py b/bindings/python/CouchbaseLite/common.py deleted file mode 100644 index 759ac8db..00000000 --- a/bindings/python/CouchbaseLite/common.py +++ /dev/null @@ -1,86 +0,0 @@ -# common.py -# -# Copyright (c) 2019 Couchbase, Inc All rights reserved. -# -# 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. -# - - -from ._PyCBL import ffi, lib - -def cstr(str): - return ffi.new("char[]", str.encode("utf-8")) - -def pystr(cstr): - return str(ffi.string(cstr), "utf-8") - -def sliceToString(s): - if s.buf == None: - return None - return str(ffi.string(ffi.cast("const char*", s.buf), s.size), "utf-8") - -def sliceResultToBytes(sr): - if sr.buf == None: - return None - return bytes( ffi.buffer(sr.buf, sr.size) ) - -def asSlice(data): - buffer = ffi.from_buffer(data) - s = ffi.new("FLSlice*") - s.buf = buffer - s.size = len(buffer) - return s - - -# A global CBLError object to use in API calls, so each call doesn't have to -# allocate a new one. (This is fine as long as we're single-threaded.) -gError = ffi.new("CBLError*") - - -class CBLException (EnvironmentError): - def __init__(self, message, cblError = None): - if cblError != None: - self.domain = cblError.domain - self.code = cblError.code - self.error = pystr(lib.CBLError_Message(cblError)) - EnvironmentError.__init__(self, message + ": " + self.error) - else: - EnvironmentError.__init__(self, message) - - -class CBLObject (object): - def __init__(self, ref, message =None, error =None): - self._ref = ref - if not ref and message: - raise CBLException(message, error) - - def __del__(self): - if lib != None and "_ref" in self.__dict__ and self._ref != None: - lib.CBL_Release(self._ref) - - -class ListenerToken (object): - def __init__(self, owner, handle, c_token): - self.owner = owner - self.handle = handle - self.c_token = c_token - - def __del__(self): - self.remove() - - def remove(self): - if self.owner != None: - lib.CBLListener_Remove(self.c_token) - self.owner.listeners.remove(self.handle) - self.owner = None - self.handle = None diff --git a/bindings/python/README.md b/bindings/python/README.md deleted file mode 100644 index bbe008d4..00000000 --- a/bindings/python/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# Python Bindings For Couchbase Lite - -10 May 2020 - -This directory contains a [Couchbase Lite][CBL] API binding for Python 3. - -It's still in early development. It's incomplete, has only had some informal testing, and that -only on macOS. - -## Building - -**_"Some assembly required..."_** - -You first need to build Couchbase Lite For C (the root of this repo) with CMake, by running the -`build.sh` script in the repo root directory. That will produce the shared library. - - $ cd ../.. - $ ./build.sh - -Then you can build the Python binding library, first installing Python's CFFI package if you haven't -already: - - $ pip install cffi - $ cd bindings/python - $ ./build.sh - -Now try the rudimentary tests: - - $ test/test.sh - -You can look at the test code in `test/test.py` for examples of how to use the API. - -## Learning - -If you're not already familiar with Couchbase Lite, you'll want to start by reading through its -[official documentation][CBLDOCS]. - -The Python API is mostly method-for-method compatible with the languages documented there, except -down at the document property level (dictionaries, arrays, etc.) where I haven't yet written -compatible bindings. For those APIs you can check out the document "[Using Fleece][FLEECE]". - -## Using - -[CBL]: https://www.couchbase.com/products/lite -[CBLDOCS]: https://docs.couchbase.com/couchbase-lite/current/introduction.html -[FLEECE]: https://github.com/couchbaselabs/fleece/wiki/Using-Fleece diff --git a/bindings/python/build.sh b/bindings/python/build.sh deleted file mode 100755 index a182d2e0..00000000 --- a/bindings/python/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/bash -e - -SCRIPT_DIR=`dirname $0` -cd $SCRIPT_DIR/CouchbaseLite -python3 ../BuildPyCBL.py $@ diff --git a/bindings/python/test/test.py b/bindings/python/test/test.py deleted file mode 100644 index 41b44191..00000000 --- a/bindings/python/test/test.py +++ /dev/null @@ -1,119 +0,0 @@ -#! /usr/bin/env python3 -# -# test.py -# -# Copyright (c) 2019 Couchbase, Inc All rights reserved. -# -# 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. -# - -from CouchbaseLite.Database import Database, DatabaseConfiguration -from CouchbaseLite.Document import Document, MutableDocument -from CouchbaseLite.Query import JSONQuery -import json - -Database.deleteFile("db", "/tmp") - -db = Database("db", DatabaseConfiguration("/tmp")) - -print ("db = ", db) -print ("name = ", db.name) -print ("dir = ", db.config) -print ("path = ", db.path) -print ("docs = ", db.count) - -assert(db.name == "db") -assert(db.path == "/tmp/db.cblite2/") -assert(db.count == 0) - -def dbListener(docIDs): - print ("######## DB changed!", docIDs) -dbListenerToken = db.addListener(dbListener) - -def canonicalJSON(str): - obj = json.loads(str) - return json.dumps(obj, sort_keys = True) - -with db: - doc = db.getDocument("foo") - assert(not doc) - doc = db.getMutableDocument("foo") - assert(not doc) - doc = MutableDocument("foo") - assert(doc.id == "foo") - - print ("doc = ", doc) - - props = doc.properties - print ("props=", props) - assert(props == {}) - - props["flavor"] = "cardamom" - props["numbers"] = [1, 0, 3.125] - doc["color"] = "green" - print ("props=", props) - - db.saveDocument(doc) - - doc2 = db.getDocument("foo") - assert(doc2.id == "foo") - print ("doc2 = ", doc2) - props2 = doc2.properties - print ("props2=", props2) - assert(props2 == props) - assert(doc2["color"] == "green") - - assert(db.count == 1) - - doc = MutableDocument("bar") - doc["color"] = "green" - doc["flavor"] = "pumpkin spice" - db["bar"] = doc # saves it - - assert(db.count == 2) - - doc = MutableDocument('nested_doc') - doc['flat'] = 'flat' - doc['empty_obj'] = {} - doc['nested'] = {'nested': 'nested'} - doc['empty_array'] = [] - doc['array'] = ['a'] - print("doc = ", canonicalJSON(doc.JSON)) - assert(canonicalJSON(doc.JSON) == """{"array": ["a"], "empty_array": [], "empty_obj": {}, "flat": "flat", "nested": {"nested": "nested"}}""") - db.saveDocument(doc) - - read_doc = db.getMutableDocument('nested_doc') - print("read_doc = ", canonicalJSON(read_doc.JSON)) - assert(canonicalJSON(read_doc.JSON) == """{"array": ["a"], "empty_array": [], "empty_obj": {}, "flat": "flat", "nested": {"nested": "nested"}}""") - db.saveDocument(read_doc) - - update_doc = db.getMutableDocument('nested_doc') - update_doc['a'] = 'b' - update_doc['nested']['foo'] = 'bar' - print("update_doc = ", canonicalJSON(update_doc.JSON)) - assert(canonicalJSON(update_doc.JSON) == """{"a": "b", "array": ["a"], "empty_array": [], "empty_obj": {}, "flat": "flat", "nested": {"foo": "bar", "nested": "nested"}}""") - db.saveDocument(update_doc) - - -dbListenerToken.remove() - -q = JSONQuery(db, {'WHAT': [['.flavor'], ['.numbers']], 'WHERE': ['=', ['.color'], 'green']}) -print ("-------- Explanation --------") -print (q.explanation) -print ("-----------------------------") -print ("Columns: ", q.columnNames) - -for row in q.execute(): - print ("row: ", row.asArray(), " ...or... ", row.asDictionary()) - -db.close() diff --git a/bindings/python/test/test.sh b/bindings/python/test/test.sh deleted file mode 100755 index 0cccb71b..00000000 --- a/bindings/python/test/test.sh +++ /dev/null @@ -1,7 +0,0 @@ -#! /bin/bash -e - -SCRIPT_DIR=`dirname $0` -cd "$SCRIPT_DIR" - -export PYTHONPATH=.. -python3 test.py diff --git a/bindings/rust/CouchbaseLite/Cargo.toml b/bindings/rust/CouchbaseLite/Cargo.toml deleted file mode 100644 index 7d5df057..00000000 --- a/bindings/rust/CouchbaseLite/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "couchbase_lite" -version = "0.1.0" -authors = ["Jens Alfke "] - -[dependencies] -enum_primitive = "*" -tempdir = "*" - -[build-dependencies] -bindgen = "0.53.1" - -[lib] -bench = false -doctest = false -crate-type = ["lib", "dylib"] - -[profile.release] -opt-level = "z" -lto = true -codegen-units = 1 -incremental = false -# See: https://github.com/johnthagen/min-sized-rust diff --git a/bindings/rust/CouchbaseLite/build.rs b/bindings/rust/CouchbaseLite/build.rs deleted file mode 100644 index d41e1938..00000000 --- a/bindings/rust/CouchbaseLite/build.rs +++ /dev/null @@ -1,120 +0,0 @@ -// Couchbase Lite C API bindings generator -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -// This script runs during a Cargo build and generates the raw/unsafe Rust bindings, "bindings.rs", -// in an internal build directory, where they are included by `src/c_api.rs`. -// -// References: -// - https://rust-lang.github.io/rust-bindgen/tutorial-3.html -// - https://doc.rust-lang.org/cargo/reference/build-scripts.html - -extern crate bindgen; - -use std::env; -use std::fs; -use std::path::PathBuf; - -//TODO: This is likely not valid for your system, but I don't know how to find it automatically -static DEFAULT_LIBCLANG_PATH : &str = "/usr/local/Cellar/llvm/10.0.0_3/lib"; - -static INCLUDE_CBL_IN_LIB : bool = false; - -fn main() { - let root_dir = PathBuf::from("../../.."); // The root of the couchbase-lite-c repo - let cbl_headers = root_dir.join("include/cbl"); - let fleece_headers = root_dir.join("vendor/couchbase-lite-core/vendor/fleece/API"); - - // Set LIBCLANG_PATH environment variable if it's not already set: - if env::var("LIBCLANG_PATH").is_err() { - env::set_var("LIBCLANG_PATH", DEFAULT_LIBCLANG_PATH); - println!("cargo:rustc-env=LIBCLANG_PATH={}", DEFAULT_LIBCLANG_PATH); - } - - // The bindgen::Builder is the main entry point - // to bindgen, and lets you build up options for - // the resulting bindings. - let bindings = bindgen::Builder::default() - // The input header we would like to generate bindings for. - .header("wrapper.h") - // C '#include' search paths: - .clang_arg("-I".to_owned() + cbl_headers.to_str().unwrap()) - .clang_arg("-I".to_owned() + fleece_headers.to_str().unwrap()) - // Which symbols to generate bindings for: - .whitelist_type("CBL.*") - .whitelist_type("FL.*") - .whitelist_var("k?CBL.*") - .whitelist_var("k?FL.*") - .whitelist_function("CBL.*") - .whitelist_function("_?FL.*") - // Tell cargo to invalidate the built crate whenever any of the - // included header files changed. - .parse_callbacks(Box::new(bindgen::CargoCallbacks)) - // Finish the builder and generate the bindings. - .generate() - // Unwrap the Result and panic on failure. - .expect("Unable to generate bindings"); - - // Write the bindings to the $OUT_DIR/bindings.rs file. - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - bindings - .write_to_file(out_dir.join("bindings.rs")) - .expect("Couldn't write bindings!"); - - // Tell cargo to tell rustc to link the cblite shared library. - //TODO: Abort the build now if the library does not exist, and tell the user to run CMake. - let root = root_dir.to_str().unwrap(); - - if INCLUDE_CBL_IN_LIB { - println!("cargo:rustc-link-search={}/build_cmake", root); - println!("cargo:rustc-link-search={}/build_cmake/vendor/couchbase-lite-core", root); - println!("cargo:rustc-link-search={}/build_cmake/vendor/couchbase-lite-core/vendor/BLIP-Cpp", root); - println!("cargo:rustc-link-search={}/build_cmake/vendor/couchbase-lite-core/vendor/fleece", root); - println!("cargo:rustc-link-search={}/build_cmake/vendor/couchbase-lite-core/vendor/mbedtls/library", root); - println!("cargo:rustc-link-search={}/build_cmake/vendor/couchbase-lite-core/vendor/sqlite3-unicodesn", root); - - println!("cargo:rustc-link-lib=static=cblite-static"); - println!("cargo:rustc-link-lib=static=FleeceStatic"); - - println!("cargo:rustc-link-lib=static=liteCoreStatic"); - println!("cargo:rustc-link-lib=static=liteCoreWebSocket"); - println!("cargo:rustc-link-lib=static=SQLite3_UnicodeSN"); - println!("cargo:rustc-link-lib=static=BLIPStatic"); - println!("cargo:rustc-link-lib=static=mbedtls"); - println!("cargo:rustc-link-lib=static=mbedcrypto"); - - println!("cargo:rustc-link-lib=c++"); - println!("cargo:rustc-link-lib=z"); - - println!("cargo:rustc-link-lib=framework=CoreFoundation"); - println!("cargo:rustc-link-lib=framework=Foundation"); - println!("cargo:rustc-link-lib=framework=CFNetwork"); - println!("cargo:rustc-link-lib=framework=Security"); - println!("cargo:rustc-link-lib=framework=SystemConfiguration"); - } else { - // Copy the CBL dylib: - let src = root_dir.join("build_cmake/libcblite.dylib"); - let dst = out_dir.join("libcblite.dylib"); - println!("cargo:rerun-if-changed={}", src.to_str().unwrap()); - fs::copy(src, dst).expect("copy dylib"); - // Tell rustc to link it: - println!("cargo:rustc-link-search={}", out_dir.to_str().unwrap()); - println!("cargo:rustc-link-lib=dylib=cblite"); - } - - // Tell cargo to invalidate the built crate whenever the wrapper changes - println!("cargo:rerun-if-changed=wrapper.h"); -} diff --git a/bindings/rust/CouchbaseLite/src/blob.rs b/bindings/rust/CouchbaseLite/src/blob.rs deleted file mode 100644 index 36ef632c..00000000 --- a/bindings/rust/CouchbaseLite/src/blob.rs +++ /dev/null @@ -1,202 +0,0 @@ -// Couchbase Lite Blob class -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -use super::*; -use crate::slice::*; -use crate::c_api::*; - -use std::ffi::c_void; -use std::marker::PhantomData; - - -/** A binary attachment to a Document. */ -pub struct Blob { - pub(crate) _ref: *const CBLBlob -} - - -impl Blob { - - //////// CREATION - - /** Creates a new blob, given its contents as a byte array. */ - pub fn new_from_data(data: &[u8], content_type: &str) -> Blob { - unsafe { - let blob = CBLBlob_CreateWithData_s(as_slice(content_type), bytes_as_slice(data)); - return Blob{_ref: blob}; - } - } - - /** Creates a new blob from data that has has been written to a [`Writer`]. - You should then add the blob to a document as a property, using [`Slot::put_blob`]. */ - pub fn new_from_stream(mut stream: BlobWriter, content_type: &str) -> Blob { - unsafe { - let blob = CBLBlob_CreateWithStream_s(as_slice(content_type), stream._stream_ref); - stream._stream_ref = std::ptr::null_mut(); // stop `drop` from closing the stream - return Blob{_ref: blob}; - } - } - - // called by FleeceReference::as_blob() - pub(crate) fn from_value(value: &V) -> Option { - unsafe { - let blob = CBLBlob_Get(FLValue_AsDict(value._fleece_ref())); - return if blob.is_null() {None} else {Some(Blob{_ref: blob})}; - } - } - - //////// ACCESSORS - - - /** The length of the content data in bytes. */ - pub fn length(&self) -> u64 { - unsafe { CBLBlob_Length(self._ref) } - } - - /** The unique digest of the blob: A base64-encoded SHA-1 digest of its data. */ - pub fn digest(&self) -> String { - unsafe { to_string(CBLBlob_Digest(self._ref)) } - } - - /** The MIME type assigned to the blob, if any. */ - pub fn content_type(&self) -> Option { - unsafe { - let cstr = CBLBlob_ContentType(self._ref); - return if cstr.is_null() { None } else { Some(to_string(cstr)) }; - } - } - - /** The blob's metadata properties as a dictionary. */ - pub fn properties(&self) -> Dict { - unsafe { Dict{_ref: CBLBlob_Properties(self._ref), _owner: PhantomData} } - } - - - //////// READING: - - /** Reads the blob's contents into memory and returns them as a byte array. - This can potentially allocate a lot of memory! */ - pub fn load_content(&self) -> Result> { - unsafe { - let mut err = CBLError::default(); - let content = CBLBlob_LoadContent(self._ref, &mut err).to_vec(); - return if let Some(c) = content { Ok(c) } else { failure(err) }; - } - } - - /** Opens a stream for reading a blob's content from disk. */ - pub fn open_content(&self) -> Result { - check_ptr(|err| unsafe{ CBLBlob_OpenContentStream(self._ref, err) }, - |stream| BlobReader{blob: self, _stream_ref: stream}) - } -} - -impl Drop for Blob { - fn drop(&mut self) { - unsafe { release(self._ref as *mut CBLBlob); } - } -} - -impl Clone for Blob { - fn clone(&self) -> Self { - unsafe { Blob{_ref: retain(self._ref as *mut CBLBlob)} } - } -} - - -//////// BLOB ADDITIONS FOR ARRAY / DICT: - - -impl Slot<'_> { - /** Stores a Blob reference in an Array or Dict. This is how you add a Blob to a Document. */ - pub fn put_blob(self, blob: &mut Blob) { - unsafe { FLSlot_SetBlob(self._ref, blob._ref as *mut CBLBlob) } - } -} - - -//////// BLOB READER - - -/** A stream for reading Blob conents. */ -pub struct BlobReader<'r> { - pub blob: &'r Blob, - _stream_ref: *mut CBLBlobReadStream -} - -impl<'r> std::io::Read for BlobReader<'r> { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - unsafe { - check_io(|err| CBLBlobReader_Read(self._stream_ref, - buf.as_mut_ptr() as *mut c_void, - buf.len() as u64, - err)) - } - } -} - -impl<'r> Drop for BlobReader<'r> { - fn drop(&mut self) { - unsafe { CBLBlobReader_Close(self._stream_ref); } - } -} - - -//////// BLOB WRITER - - -/** A stream for writing data that will become a Blob's contents. - After you're done writing the data, call [`Blob::new_from_stream`], - then add the Blob to a document property via [`Slot::put_blob`]. */ -pub struct BlobWriter<'d> { - _stream_ref: *mut CBLBlobWriteStream, - db: PhantomData<&'d mut Database> -} - -impl<'d> BlobWriter<'d> { - pub fn new(db: &'d mut Database) -> Result> { - unsafe { - let db_ref = db._ref; - check_ptr(|err| CBLBlobWriter_New(db_ref, err), - move |stream| BlobWriter{_stream_ref: stream, db: PhantomData}) - } - } -} - -impl<'r> std::io::Write for BlobWriter<'r> { - fn write(&mut self, data: &[u8]) -> std::result::Result { - unsafe { - check_io(|err| { - let ok = CBLBlobWriter_Write(self._stream_ref, - data.as_ptr() as *const c_void, - data.len() as u64, - err); - if ok {data.len() as i32} else {-1} - }) - } - } - - fn flush(&mut self) -> std::result::Result<(), std::io::Error> { - Ok(()) - } -} - -impl<'r> Drop for BlobWriter<'r> { - fn drop(&mut self) { - unsafe { CBLBlobWriter_Close(self._stream_ref) } - } -} diff --git a/bindings/rust/CouchbaseLite/src/database.rs b/bindings/rust/CouchbaseLite/src/database.rs deleted file mode 100644 index ae54af02..00000000 --- a/bindings/rust/CouchbaseLite/src/database.rs +++ /dev/null @@ -1,224 +0,0 @@ -// Couchbase Lite database API -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -use super::*; -use super::slice::*; -use super::error::*; -use super::c_api::*; - -use std::path::*; -use std::ptr; - - -// Database configuration flags: -pub static CREATE : u32 = kCBLDatabase_Create; -pub static READ_ONLY : u32 = kCBLDatabase_ReadOnly; -pub static NO_UPGRADE : u32 = kCBLDatabase_NoUpgrade; - - -/** Database configuration options. */ -pub struct DatabaseConfiguration<'a> { - pub directory: &'a std::path::Path, - pub flags: u32 -} - - -type ChangeListener = fn(db: &Database, doc_ids: Vec); - - -/** A connection to an open database. */ -pub struct Database { - pub(crate) _ref: *mut CBLDatabase -} - - -impl Database { - - //////// CONSTRUCTORS: - - - /** Opens a database, or creates it if it doesn't exist yet, returning a new `Database` - instance. - - It's OK to open the same database file multiple times. Each `Database` instance is - independent of the others (and must be separately closed and released.) */ - pub fn open(name: &str, config: Option) -> Result { - unsafe { - if let Some(cfg) = config { - let c_config = CBLDatabaseConfiguration_s { - directory: as_slice(cfg.directory.to_str().unwrap()), - flags: cfg.flags, - encryptionKey: ptr::null_mut() // TODO - }; - return Database::_open(name, &c_config); - } else { - return Database::_open(name, ptr::null()) - } - } - } - - - unsafe fn _open(name: &str, config_ptr: *const CBLDatabaseConfiguration_s) -> Result { - let mut err = CBLError::default(); - let db_ref = CBLDatabase_Open_s(as_slice(name), config_ptr, &mut err); - if db_ref.is_null() { - return failure(err); - } - return Ok(Database{_ref: db_ref}); - } - - - //////// OTHER STATIC METHODS: - - - /** Returns true if a database with the given name exists in the given directory. */ - pub fn exists>(name: &str, in_directory: P) -> bool { - unsafe { - return CBL_DatabaseExists_s(as_slice(name), - as_slice(in_directory.as_ref().to_str().unwrap())); - } - } - - - /** Deletes a database file. If the database file is open, an error is returned. */ - pub fn delete_file>(name: &str, in_directory: P) -> Result { - unsafe { - let mut error = CBLError::default(); - if CBL_DeleteDatabase_s(as_slice(name), - as_slice(in_directory.as_ref().to_str().unwrap()), - &mut error) { - return Ok(true); - } else if !error { - return Ok(false); - } else { - return failure(error); - } - } - } - - - //////// OPERATIONS: - - - /** Closes and deletes a database. If there are any other connections to the database, - an error is returned. */ - pub fn delete(self) -> Result<()> { - unsafe { check_bool(|error| CBLDatabase_Delete(self._ref, error)) } - } - - - /** Compacts a database file, freeing up unused disk space. */ - pub fn compact(&mut self) -> Result<()> { - unsafe { - return check_bool(|error| CBLDatabase_Compact(self._ref, error)); - } - } - - - /** Invokes the callback as a batch operation, similar to a transaction. - - Multiple writes are much faster when grouped inside a single batch. - - Changes will not be visible to other Database instances on the same database until - the batch operation ends. - - Batch operations can nest. Changes are not committed until the outer batch ends. */ - pub fn in_batch(&self, callback: fn()->T) -> Result { - let mut err = CBLError::default(); - unsafe { - if ! CBLDatabase_BeginBatch(self._ref, &mut err) { - return failure(err); - } - } - let result = callback(); - unsafe { - if ! CBLDatabase_EndBatch(self._ref, &mut err) { - return failure(err); - } - } - return Ok(result); - } - - - //////// ACCESSORS: - - - /** Returns the database's name. */ - pub fn name(&self) -> String { - unsafe { - return to_string(CBLDatabase_Name(self._ref)); - } - } - - - /** Returns the database's full filesystem path. */ - pub fn path(&self) -> PathBuf { - unsafe { - return PathBuf::from(to_string(CBLDatabase_Path(self._ref))); - } - } - - - /** Returns the number of documents in the database. */ - pub fn count(&self) -> u64 { - unsafe { - return CBLDatabase_Count(self._ref); - } - } - - - //////// NOTIFICATIONS: - - - /** Registers a database change listener function. It will be called after one or more - documents are changed on disk. */ - pub fn add_listener(&self, _listener: ChangeListener) -> ListenerToken { - todo!() - } - - /** Switches the database to buffered-notification mode. Notifications for objects belonging - to this database (documents, queries, replicators, and of course the database) will not be - called immediately; your callback function will be called instead. You can then call - `send_notifications` when you're ready. */ - pub fn buffer_notifications(&self, _callback: fn(&Database)) { - todo!() - } - - /** Immediately issues all pending notifications for this database, by calling their listener - callbacks. (Only useful after `buffer_notifications` has been called.) */ - pub fn send_notifications(&self) { - unsafe { - CBLDatabase_SendNotifications(self._ref); - } - } - -} - - -impl Drop for Database { - fn drop(&mut self) { - unsafe { - release(self._ref) - } - } -} - - -impl Clone for Database { - fn clone(&self) -> Self { - unsafe { - return Database{_ref: retain(self._ref)} - } - } -} diff --git a/bindings/rust/CouchbaseLite/src/document.rs b/bindings/rust/CouchbaseLite/src/document.rs deleted file mode 100644 index 045394d5..00000000 --- a/bindings/rust/CouchbaseLite/src/document.rs +++ /dev/null @@ -1,231 +0,0 @@ -// Couchbase Lite document API -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -use super::*; -use super::slice::*; -use super::c_api::*; - - -/** An in-memory copy of a document. */ -pub struct Document { - _ref: *mut CBLDocument -} - - -//////// DATABASE'S DOCUMENT API: - - -/** Conflict-handling options when saving or deleting a document. */ -pub enum ConcurrencyControl { - LastWriteWins = kCBLConcurrencyControlLastWriteWins as isize, - FailOnConflict = kCBLConcurrencyControlFailOnConflict as isize -} - - -pub type SaveConflictHandler = fn(&mut Document, &Document) -> bool; - -pub type ChangeListener = fn(&Database, &str); - - -impl Database { - /** Reads a document from the database. Each call to this function returns a new object - containing the document's current state. */ - pub fn get_document(&self, id: &str) -> Result { - unsafe { - // we always get a mutable CBLDocument, - // since Rust doesn't let us have MutableDocument subclass. - let doc = CBLDatabase_GetMutableDocument_s(self._ref, as_slice(id)); - if doc.is_null() { - return Err(Error::cbl_error(CouchbaseLiteError::NotFound)); - } - return Ok(Document{_ref: doc}); - } - } - - /** Saves a new or modified document to the database. - If a conflicting revision has been saved since `doc` was loaded, the `concurrency` - parameter specifies whether the save should fail, or the conflicting revision should - be overwritten with the revision being saved. - If you need finer-grained control, call `save_document_resolving` instead. */ - pub fn save_document(&mut self, - doc: &mut Document, - concurrency: ConcurrencyControl) - -> Result - { - let mut error = CBLError::default(); - unsafe { - let doc2 = CBLDatabase_SaveDocument(self._ref, doc._ref, concurrency as u8, &mut error); - if doc2.is_null() { - return failure(error); - } - return Ok(Document{_ref: doc2 as *mut CBLDocument}); - } - } - - /** Saves a new or modified document to the database. This function is the same as - `save_document`, except that it allows for custom conflict handling in the event - that the document has been updated since `doc` was loaded. */ - pub fn save_document_resolving(&mut self, - _doc: &mut Document, - _conflict_handler: SaveConflictHandler) - -> Result - { - todo!() - } - - pub fn purge_document_by_id(&mut self, id: &str) -> Result<()> { - unsafe { - return check_bool(|error| CBLDatabase_PurgeDocumentByID_s(self._ref, as_slice(id), error)); - } - } - - /** Returns the time, if any, at which a given document will expire and be purged. - Documents don't normally expire; you have to call `set_document_expiration` - to set a document's expiration time. */ - pub fn document_expiration(&self, doc_id: &str) -> Result> { - unsafe { - let mut error = CBLError::default(); - let exp = CBLDatabase_GetDocumentExpiration_s(self._ref, as_slice(doc_id), &mut error); - if exp < 0 { - return failure(error); - } else if exp == 0 { - return Ok(None); - } else { - return Ok(Some(Timestamp(exp))); - } - } - } - - /** Sets or clears the expiration time of a document. */ - pub fn set_document_expiration(&mut self, doc_id: &str, when: Option) -> Result<()> { - let exp :i64 = match when { - Some(Timestamp(n)) => n, - _ => 0, - }; - unsafe { - return check_bool(|error| CBLDatabase_SetDocumentExpiration_s(self._ref, as_slice(doc_id), exp, error)); - } - } - - /** Registers a document change listener callback. It will be called after a specific document - is changed on disk. */ - pub fn add_document_change_listener(&self, _doc_id: &str, _listener: ChangeListener) -> ListenerToken { - todo!() - } - -} - - -//////// DOCUMENT API: - - -impl Document { - - /** Creates a new, empty document in memory, with an automatically generated unique ID. - It will not be added to a database until saved. */ - pub fn new() -> Self { - unsafe { Document{_ref: CBLDocument_New_s(NULL_SLICE)} } - } - - /** Creates a new, empty document in memory, with the given ID. - It will not be added to a database until saved. */ - pub fn new_with_id(id: &str) -> Self { - unsafe { Document{_ref: CBLDocument_New_s(as_slice(id))} } - } - - /** Deletes a document from the database. (Deletions are replicated, unlike purges.) */ - pub fn delete(self) -> Result<()> { - todo!() - } - - /** Purges a document. This removes all traces of the document from the database. - Purges are _not_ replicated. If the document is changed on a server, it will be re-created - when pulled. */ - pub fn purge(self) -> Result<()> { - todo!() - } - - /** Returns the document's ID. */ - pub fn id(&self) -> String { - unsafe { to_string(CBLDocument_ID(self._ref)) } - } - - /** Returns a document's revision ID, which is a short opaque string that's guaranteed to be - unique to every change made to the document. - If the document doesn't exist yet, this method returns None. */ - pub fn revision_id(&self) -> Option { - unsafe { - let revid = CBLDocument_RevisionID(self._ref); - return if revid.is_null() {None} else {Some(to_string(revid))} - } - } - - /** Returns a document's current sequence in the local database. - This number increases every time the document is saved, and a more recently saved document - will have a greater sequence number than one saved earlier, so sequences may be used as an - abstract 'clock' to tell relative modification times. */ - pub fn sequence(&self) -> u64 { - unsafe { CBLDocument_Sequence(self._ref) } - } - - /** Returns a document's properties as a dictionary. - This dictionary cannot be mutated; call `mutable_properties` if you want to make - changes to the document's properties. */ - pub fn properties<'a>(&'a self) -> Dict { - unsafe { Dict::wrap(CBLDocument_Properties(self._ref), self) } - } - - /** Returns a document's properties as an mutable dictionary. Any changes made to this - dictionary will be saved to the database when this Document instance is saved. */ - pub fn mutable_properties(&mut self) -> MutableDict { - unsafe { MutableDict::adopt(CBLDocument_MutableProperties(self._ref)) } - } - - /** Replaces a document's properties with the contents of the dictionary. - The dictionary is retained, not copied, so further changes _will_ affect the document. */ - pub fn set_properties(&mut self, properties: MutableDict) { - unsafe { CBLDocument_SetProperties(self._ref, properties._ref) } - } - - /** Returns a document's properties as a JSON string. */ - pub fn properties_as_json(&self) -> String { - unsafe { to_string(CBLDocument_PropertiesAsJSON(self._ref)) } - } - - /** Sets a mutable document's properties from a JSON string. */ - pub fn set_properties_as_json(&mut self, json: &str) -> Result<()> { - unsafe { - let mut err = CBLError::default(); - let ok = CBLDocument_SetPropertiesAsJSON_s(self._ref, as_slice(json), &mut err); - return check_failure(ok, &err); - } - } -} - - -impl Drop for Document { - fn drop(&mut self) { - unsafe { release(self._ref); } - } -} - - -impl Clone for Document { - fn clone(&self) -> Self { - unsafe { Document{_ref: retain(self._ref)} } - } -} diff --git a/bindings/rust/CouchbaseLite/src/error.rs b/bindings/rust/CouchbaseLite/src/error.rs deleted file mode 100644 index f34b95e2..00000000 --- a/bindings/rust/CouchbaseLite/src/error.rs +++ /dev/null @@ -1,286 +0,0 @@ -// Couchbase Lite error classs -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -#![allow(non_upper_case_globals)] - -use super::c_api::*; -use enum_primitive::FromPrimitive; -use std::fmt; - - -//////// ERROR STRUCT: - - -/** Error type. Wraps multiple types of errors in an enum. */ -pub struct Error { - pub code: ErrorCode, - pub(crate) internal_info: Option -} - - -/** The enum that stores the error domain and code for an Error. */ -#[derive(Debug, PartialEq)] -pub enum ErrorCode { - CouchbaseLite (CouchbaseLiteError), - POSIX (i32), - SQLite (i32), - Fleece (FleeceError), - Network (NetworkError), - WebSocket (i32) -} - -// Redefine `Result` to assume our `Error` type -pub type Result = std::result::Result; - - -enum_from_primitive! { - /** Couchbase Lite error codes. */ - #[derive(Debug, Copy, Clone, PartialEq)] - pub enum CouchbaseLiteError { - AssertionFailed = 1, // Internal assertion failure - Unimplemented, // Oops, an unimplemented API call - UnsupportedEncryption, // Unsupported encryption algorithm - BadRevisionID, // Invalid revision ID syntax - CorruptRevisionData, // Revision contains corrupted/unreadable data - NotOpen, // Database/KeyStore/index is not open - NotFound, // Document not found - Conflict, // Document update conflict - InvalidParameter, // Invalid function parameter or struct value - UnexpectedError, /*10*/ // Internal unexpected C++ exception - CantOpenFile, // Database file can't be opened; may not exist - IOError, // File I/O error - MemoryError, // Memory allocation failed (out of memory?) - NotWriteable, // File is not writeable - CorruptData, // Data is corrupted - Busy, // Database is busy/locked - NotInTransaction, // Function must be called while in a transaction - TransactionNotClosed, // Database can't be closed while a transaction is open - Unsupported, // Operation not supported in this database - NotADatabaseFile,/*20*/ // File is not a database, or encryption key is wrong - WrongFormat, // Database exists but not in the format/storage requested - Crypto, // Encryption/decryption error - InvalidQuery, // Invalid query - MissingIndex, // No such index, or query requires a nonexistent index - InvalidQueryParam, // Unknown query param name, or param number out of range - RemoteError, // Unknown error from remote server - DatabaseTooOld, // Database file format is older than what I can open - DatabaseTooNew, // Database file format is newer than what I can open - BadDocID, // Invalid document ID - CantUpgradeDatabase,/*30*/ // DB can't be upgraded (might be unsupported dev version) - - UntranslatableError = 1000, // Can't translate native error (unknown domain or code) - } -} - -enum_from_primitive! { - /** Fleece error codes. */ - #[derive(Debug, Copy, Clone, PartialEq)] - pub enum FleeceError { - MemoryError = 1, // Out of memory, or allocation failed - OutOfRange, // Array index or iterator out of range - InvalidData, // Bad input data (NaN, non-string key, etc.) - EncodeError, // Structural error encoding (missing value, too many ends, etc.) - JSONError, // Error parsing JSON - UnknownValue, // Unparseable data in a Value (corrupt? Or from some distant future?) - InternalError, // Something that shouldn't happen - NotFound, // Key not found - SharedKeysStateError, // Misuse of shared keys (not in transaction, etc.) - POSIXError, // Something went wrong at the OS level (file I/O, etc.) - Unsupported, // Operation is unsupported - } -} - -enum_from_primitive! { - /** Network error codes defined by Couchbase Lite. */ - #[derive(Debug, Copy, Clone, PartialEq)] - pub enum NetworkError { - DNSFailure = 1, // DNS lookup failed - UnknownHost, // DNS server doesn't know the hostname - Timeout, // No response received before timeout - InvalidURL, // Invalid URL - TooManyRedirects, // HTTP redirect loop - TLSHandshakeFailed, // Low-level error establishing TLS - TLSCertExpired, // Server's TLS certificate has expired - TLSCertUntrusted, // Cert isn't trusted for other reason - TLSClientCertRequired, // Server requires client to have a TLS certificate - TLSClientCertRejected, // Server rejected my TLS client certificate - TLSCertUnknownRoot, // Self-signed cert, or unknown anchor cert - InvalidRedirect, // Attempted redirect to invalid URL - Unknown, // Unknown networking error - TLSCertRevoked, // Server's cert has been revoked - TLSCertNameMismatch, // Server cert's name does not match DNS name - } -} - - -impl Error { - pub(crate) fn new(err: &CBLError) -> Error { - Error{code: ErrorCode::new(err), internal_info: Some(err.internal_info)} - } - - pub(crate) fn cbl_error(e: CouchbaseLiteError) -> Error { - Error{code: ErrorCode::CouchbaseLite(e), internal_info: None} - } - - pub(crate) fn fleece_error(e: FLError) -> Error { - Error{code: ErrorCode::from_fleece(e), internal_info: None} - } - - pub(crate) fn as_cbl_error(&self) -> CBLError { - let domain: CBLErrorDomain; - let code: i32; - match &self.code { - ErrorCode::CouchbaseLite(e) => {domain = CBLDomain; code = *e as i32;}, - ErrorCode::Fleece(e) => {domain = CBLFleeceDomain; code = *e as i32;}, - ErrorCode::Network(e) => {domain = CBLNetworkDomain; code = *e as i32;}, - ErrorCode::POSIX(e) => {domain = CBLPOSIXDomain; code = *e as i32;}, - ErrorCode::SQLite(e) => {domain = CBLSQLiteDomain; code = *e as i32;} - ErrorCode::WebSocket(e) => {domain = CBLWebSocketDomain; code = *e as i32;} - } - return CBLError{domain: domain, code: code, internal_info: self.internal_info.unwrap_or(0)} - } - - pub fn message(&self) -> String { - if let ErrorCode::CouchbaseLite(e) = self.code { - if e == CouchbaseLiteError::UntranslatableError { - return "Unknown error".to_string(); - } - } - unsafe { CBLError_Message_s(&self.as_cbl_error()).to_string().unwrap() } - } -} - -impl std::error::Error for Error { } -impl std::error::Error for &Error { } - -impl fmt::Debug for Error { - fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> { - return fmt.write_fmt(format_args!("{:?}: {})", self.code, self.message())); - } -} - -impl fmt::Display for Error { - fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> { - return fmt.write_str(&self.message()); - } -} - - -impl ErrorCode { - fn new(err: &CBLError) -> ErrorCode { - match err.domain { - CBLDomain => { - if let Some(e) = CouchbaseLiteError::from_i32(err.code) { - return ErrorCode::CouchbaseLite(e) - } - } - CBLNetworkDomain => { - if let Some(e) = NetworkError::from_i32(err.code as i32) { - return ErrorCode::Network(e) - } - } - CBLPOSIXDomain => return ErrorCode::POSIX(err.code), - CBLSQLiteDomain => return ErrorCode::SQLite(err.code), - CBLFleeceDomain => return ErrorCode::from_fleece(err.code as u32), - CBLWebSocketDomain => return ErrorCode::WebSocket(err.code), - _ => { } - } - return ErrorCode::untranslatable(); - } - - fn from_fleece(fleece_error: u32) -> ErrorCode { - if let Some(e) = FleeceError::from_u32(fleece_error) { - return ErrorCode::Fleece(e) - } - return ErrorCode::untranslatable() - } - - fn untranslatable() -> ErrorCode { - ErrorCode::CouchbaseLite(CouchbaseLiteError::UntranslatableError) - } -} - - -//////// CBLERROR UTILITIES: - - -impl Default for CBLError { - fn default() -> CBLError { CBLError{domain: 0, code: 0, internal_info: 0} } -} - -impl std::ops::Not for CBLError { - type Output = bool; - fn not(self) -> bool {self.code == 0} -} - -impl std::ops::Not for &CBLError { - type Output = bool; - fn not(self) -> bool {self.code == 0} -} - - -// Convenient way to return a Result from a failed CBLError -pub(crate) fn failure(err: CBLError) -> Result { - assert!(err.code != 0); - return Err(Error::new(&err)); -} - -pub(crate) fn check_failure(status: bool, err: &CBLError) -> Result<()> { - if status { - return Ok(()); - } else { - assert!(err.code != 0); - return Err(Error::new(err)); - } -} - -pub(crate) fn check_bool(func: F) -> Result<()> - where F: Fn(*mut CBLError)->bool -{ - let mut error = CBLError::default(); - let ok = func(&mut error); - return check_failure(ok, &error); -} - -// The first parameter is a function that returns a non-null pointer or sets the error. -// The second parameter is a function that takes the returned pointer and returns the final result. -pub(crate) fn check_ptr(func: F, map: MAPF) -> Result - where F: Fn(*mut CBLError)->*mut PTR, - MAPF: FnOnce(*mut PTR) -> RESULT -{ - let mut error = CBLError::default(); - let ptr = func(&mut error); - return if ptr.is_null() {failure(error)} else {Ok(map(ptr))}; -} - -// The first parameter is a function that returns a non-null pointer or sets the error. -// The second parameter is a function that takes the returned pointer and returns the final result. -pub(crate) fn check_io(mut func: F) -> std::io::Result - where F: FnMut(*mut CBLError)->i32 -{ - let mut error = CBLError::default(); - let n = func(&mut error); - if n < 0 { - // TODO: Better error mapping! - return Err(std::io::Error::new(std::io::ErrorKind::NotFound, Error::new(&error))); - } else { - return Ok(n as usize); - } -} - - - diff --git a/bindings/rust/CouchbaseLite/src/fleece.rs b/bindings/rust/CouchbaseLite/src/fleece.rs deleted file mode 100644 index d4c9db3d..00000000 --- a/bindings/rust/CouchbaseLite/src/fleece.rs +++ /dev/null @@ -1,483 +0,0 @@ -// Fleece API bindings, for Couchbase Lite document properties -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -use super::*; -use super::slice::*; -use super::error::*; -use super::c_api::*; - -use enum_primitive::FromPrimitive; -use std::fmt; -use std::marker::PhantomData; -use std::mem::MaybeUninit; -use std::ptr; -use std::str; - - -//////// CONTAINER - - -pub enum Trust { - Untrusted, - Trusted, -} - -/// Equivalent to FLDoc -pub struct Fleece { - pub(crate) _ref: FLDoc, -} - -impl Fleece { - pub fn parse(data: &[u8], trust: Trust) -> Result { - unsafe { - let mut copied = FLSlice_Copy(bytes_as_slice(data)); - let doc = FLDoc_FromResultData(copied, trust as u32, ptr::null_mut(), NULL_SLICE); - if doc.is_null() { - copied.release(); - return Err(Error::fleece_error(FLError_kFLInvalidData)); - } - return Ok(Fleece{_ref: doc}); - } - } - - pub fn parse_json(json: &str) -> Result { - unsafe { - let mut error: FLError = 0; - let doc = FLDoc_FromJSON(as_slice(json), &mut error); - if doc.is_null() { - return Err(Error::fleece_error(error)); - } - return Ok(Fleece{_ref: doc}); - } - } - - pub fn root(&self) -> Value { - unsafe { - Value::wrap(FLDoc_GetRoot(self._ref), self) - } - } - - pub fn as_array(&self) -> Array { - self.root().as_array() - } - - pub fn as_dict(&self) -> Dict { - self.root().as_dict() - } - - pub fn data<'a>(&self) -> &'a[u8] { - unsafe { - return FLDoc_GetData(self._ref).as_byte_array().unwrap(); - } - } -} - -impl Drop for Fleece { - fn drop(&mut self) { - unsafe { - FLDoc_Release(self._ref); - } - } -} - -impl Clone for Fleece { - fn clone(&self) -> Self { - unsafe { - return Fleece{_ref: FLDoc_Retain(self._ref)} - } - } -} - - -//////// VALUE - - -enum_from_primitive! { - #[derive(Debug, PartialEq)] - pub enum ValueType { - Undefined = -1, // Type of a NULL pointer, i.e. no such value, like JSON `undefined` - Null = 0, // Equivalent to a JSON 'null' - Bool, // A `true` or `false` value - Number, // A numeric value, either integer or floating-point - String, // A string - Data, // Binary data (no JSON equivalent) - Array, // An array of values - Dict // A mapping of strings to values - } -} - - -/** A trait for Value, Array and Dict. */ -pub trait FleeceReference : Default + PartialEq + Eq + std::ops::Not + fmt::Debug + fmt::Display { - fn _fleece_ref(&self) -> FLValue; // not for public consumption - - fn as_value(&self) -> Value { Value{_ref: self._fleece_ref(), _owner: PhantomData} } - - fn to_json(&self) -> String { - unsafe { FLValue_ToJSON(self._fleece_ref()).to_string().unwrap() } - } - - // Blob accessors: - - fn is_blob(&self) -> bool { - unsafe { CBL_IsBlob(FLValue_AsDict(self._fleece_ref())) } - } - - fn as_blob(&self) -> Option { - Blob::from_value(self) - } - -} - - -/** A Fleece value. It could be any type, including Undefined (empty). */ -#[derive(Clone, Copy)] -pub struct Value<'f> { - pub(crate) _ref: FLValue, - pub(crate) _owner : PhantomData<&'f Fleece> -} - - -impl<'f> Value<'f> { - pub const UNDEFINED : Value<'static> = Value{_ref: ptr::null(), _owner: PhantomData}; - - pub(crate) fn wrap<'a, T>(value: FLValue, _owner: &'a T) -> Value<'a> { - Value{_ref: value, _owner: PhantomData} - } - - pub fn get_type(&self) -> ValueType { - unsafe { return ValueType::from_i32(FLValue_GetType(self._ref)).unwrap(); } - } - pub fn is_type(&self, t: ValueType) -> bool { self.get_type() == t } - - pub fn is_number(&self) -> bool {self.is_type(ValueType::Number)} - pub fn is_integer(&self) -> bool {unsafe { FLValue_IsInteger(self._ref) } } - - pub fn as_i64(&self) -> Option {if self.is_integer() {Some(self.as_i64_or_0())} else {None} } - pub fn as_u64(&self) -> Option {if self.is_integer() {Some(self.as_u64_or_0())} else {None} } - pub fn as_f64(&self) -> Option {if self.is_number() {Some(self.as_f64_or_0())} else {None} } - pub fn as_f32(&self) -> Option {if self.is_number() {Some(self.as_f32_or_0())} else {None} } - pub fn as_bool(&self)-> Option {if self.is_type(ValueType::Bool) {Some(self.as_bool_or_false())} else {None} } - - pub fn as_i64_or_0(&self) -> i64 {unsafe { FLValue_AsInt(self._ref) } } - pub fn as_u64_or_0(&self) -> u64 {unsafe { FLValue_AsUnsigned(self._ref) } } - pub fn as_f64_or_0(&self) -> f64 {unsafe { FLValue_AsDouble(self._ref) } } - pub fn as_f32_or_0(&self) -> f32 {unsafe { FLValue_AsFloat(self._ref) } } - pub fn as_bool_or_false(&self) -> bool {unsafe { FLValue_AsBool(self._ref) } } - - pub fn as_timestamp(&self) -> Option { - unsafe { - let t = FLValue_AsTimestamp(self._ref); - if t == 0 { - return None; - } - return Some(Timestamp(t)); - } - } - - pub fn as_string(&self) -> Option<&'f str> { - unsafe { FLValue_AsString(self._ref).as_str() } - } - - pub fn as_data(&self) -> Option<&'f [u8]> { - unsafe { FLValue_AsData(self._ref).as_byte_array() } - } - - pub fn as_array(&self) -> Array<'f> { - unsafe { Array{_ref: FLValue_AsArray(self._ref), _owner: self._owner} } - } - - pub fn as_dict(&self) -> Dict<'f> { - unsafe { Dict{_ref: FLValue_AsDict(self._ref), _owner: self._owner} } - } -} - -impl<'f> FleeceReference for Value<'f> { - fn _fleece_ref(&self) -> FLValue { self._ref } -} - -impl Default for Value<'_> { - fn default() -> Value<'static> { Value::UNDEFINED } -} - -impl PartialEq for Value<'_> { - fn eq(&self, other: &Self) -> bool { - unsafe { FLValue_IsEqual(self._ref, other._ref) } - } -} - -impl Eq for Value<'_> { } - -impl std::ops::Not for Value<'_> { - type Output = bool; - fn not(self) -> bool {self._ref.is_null()} -} - -impl fmt::Debug for Value<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Value") - .field("type", &self.get_type()) - .finish() - } -} - -impl fmt::Display for Value<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - return f.write_str(&self.to_json()); - } -} - - -//////// ARRAY - - -/** A Fleece array value. */ -#[derive(Clone, Copy)] -pub struct Array<'f> { - pub(crate) _ref: FLArray, - pub(crate) _owner : PhantomData<&'f Fleece> -} - -impl<'f> Array<'f> { - pub(crate) fn wrap<'a, T>(array: FLArray, _owner: &'a T) -> Array<'a> { - Array{_ref: array, _owner: PhantomData} - } - - pub fn count(&self) -> u32 { unsafe { FLArray_Count(self._ref) }} - pub fn empty(&self) -> bool { unsafe { FLArray_IsEmpty(self._ref) }} - - pub fn get(&self, index: u32) -> Value<'f> { - unsafe { Value{_ref: FLArray_Get(self._ref, index), _owner: self._owner} } - } - - pub fn iter(&self) -> ArrayIterator<'f> { - unsafe { - let mut i = MaybeUninit::::uninit(); - FLArrayIterator_Begin(self._ref, i.as_mut_ptr()); - return ArrayIterator{_innards: i.assume_init(), _owner: self._owner}; - } - } -} - -impl<'f> FleeceReference for Array<'f> { - fn _fleece_ref(&self) -> FLValue { self._ref as FLValue } -} - -impl Default for Array<'_> { - fn default() -> Array<'static> { Array{_ref: ptr::null(), _owner: PhantomData} } -} - -impl PartialEq for Array<'_> { - fn eq(&self, other: &Self) -> bool { self.as_value() == other.as_value() } -} - -impl Eq for Array<'_> { } - -impl std::ops::Not for Array<'_> { - type Output = bool; - fn not(self) -> bool {self._ref.is_null()} -} - -impl fmt::Debug for Array<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Array") - .field("count", &self.count()) - .finish() - } -} - -impl fmt::Display for Array<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - return f.write_str(&self.as_value().to_json()); - } -} - -impl<'a> IntoIterator for Array<'a> { - type Item = Value<'a>; - type IntoIter = ArrayIterator<'a>; - fn into_iter(self) -> Self::IntoIter { self.iter() } -} - -// This doesn't work because it requires the return value be a ref! -// impl std::ops::Index for Array { -// type Output = Value; -// fn index(&self, index: usize) -> Value { self.get(index) } -// } - - -//////// ARRAY ITERATOR - - -pub struct ArrayIterator<'a> { - _innards : FLArrayIterator, - _owner : PhantomData<&'a Fleece> -} - -impl<'a> ArrayIterator<'a> { - pub fn count(&self) -> u32 { - unsafe { FLArrayIterator_GetCount(&self._innards) } - } - - pub fn get(&self, index: usize) -> Value { - unsafe { - Value::wrap(FLArrayIterator_GetValueAt(&self._innards, index as u32), self) - } - } -} - -impl<'f> Iterator for ArrayIterator<'f> { - type Item = Value<'f>; - - fn next(&mut self) -> Option> { - unsafe { - let val = FLArrayIterator_GetValue(&self._innards); - if val.is_null() { - return None; - } - FLArrayIterator_Next(&mut self._innards); - return Some(Value{_ref: val, _owner: PhantomData}); - } - } -} -//TODO: Implement FusedIterator, ExactSizeIterator, FromIterator - - -//////// DICT - - -/** A Fleece dictionary (object) value. */ -#[derive(Clone, Copy)] -pub struct Dict<'f> { - pub(crate) _ref: FLDict, - pub(crate) _owner : PhantomData<&'f Fleece> -} - -impl<'f> Dict<'f> { - pub(crate) fn wrap<'a, T>(dict: FLDict, _owner: &'a T) -> Dict<'a> { Dict{_ref: dict, _owner: PhantomData} } - - pub fn as_value(&self) -> Value<'f> { Value{_ref: self._ref as FLValue, _owner: self._owner} } - - pub fn count(&self) -> u32 { unsafe { FLDict_Count(self._ref) }} - pub fn empty(&self) -> bool { unsafe { FLDict_IsEmpty(self._ref) }} - - pub fn get(&self, key: &str) -> Value<'f> { - unsafe { Value{_ref: FLDict_Get(self._ref, as_slice(key)), _owner: self._owner} } - } - - pub fn get_key(&self, key: &mut DictKey) -> Value<'f> { - unsafe { Value{_ref: FLDict_GetWithKey(self._ref, &mut key._innards), _owner: self._owner} } - } - - pub fn iter(&self) -> DictIterator<'f> { - unsafe { - let mut i = MaybeUninit::::uninit(); - FLDictIterator_Begin(self._ref, i.as_mut_ptr()); - return DictIterator{_innards: i.assume_init(), _owner: self._owner}; - } - } -} - -impl<'f> FleeceReference for Dict<'f> { - fn _fleece_ref(&self) -> FLValue { self._ref as FLValue } -} - -impl Default for Dict<'_> { - fn default() -> Dict<'static> { Dict{_ref: ptr::null(), _owner: PhantomData} } -} - -impl PartialEq for Dict<'_> { - fn eq(&self, other: &Self) -> bool { self.as_value() == other.as_value() } -} - -impl Eq for Dict<'_> { } - -impl std::ops::Not for Dict<'_> { - type Output = bool; - fn not(self) -> bool {self._ref.is_null()} -} - -impl fmt::Debug for Dict<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Dict") - .field("count", &self.count()) - .finish() - } -} - -impl fmt::Display for Dict<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - return f.write_str(&self.as_value().to_json()); - } -} - -impl<'a> IntoIterator for Dict<'a> { - type Item = (&'a str, Value<'a>); - type IntoIter = DictIterator<'a>; - fn into_iter(self) -> Self::IntoIter { self.iter() } -} - - -//////// DICT KEY - - -pub struct DictKey { - pub(crate) _innards: FLDictKey -} - -impl DictKey { - pub fn new(key: &str) -> DictKey { - unsafe { - return DictKey{_innards: FLDictKey_Init(as_slice(key))}; - } - } - - pub fn string(&self) -> &str { - unsafe { FLDictKey_GetString(&self._innards).as_str().unwrap() } - } -} - - -//////// DICT ITERATOR - - -pub struct DictIterator<'a> { - _innards : FLDictIterator, - _owner : PhantomData<&'a Fleece> -} - -impl<'a> DictIterator<'a> { - pub fn count(&self) -> u32 { - unsafe { FLDictIterator_GetCount(&self._innards) } - } -} - -impl<'a> Iterator for DictIterator<'a> { - type Item = (&'a str, Value<'a>); - - fn next(&mut self) -> Option { - unsafe { - let val = FLDictIterator_GetValue(&self._innards); - if val.is_null() { - return None; - } - let key = FLDictIterator_GetKeyString(&self._innards).as_str().unwrap(); - FLDictIterator_Next(&mut self._innards); - return Some( (key, Value{_ref: val, _owner: PhantomData}) ); - } - } -} -//TODO: Implement FusedIterator, ExactSizeIterator, FromIterator diff --git a/bindings/rust/CouchbaseLite/src/fleece_mutable.rs b/bindings/rust/CouchbaseLite/src/fleece_mutable.rs deleted file mode 100644 index 05831fe1..00000000 --- a/bindings/rust/CouchbaseLite/src/fleece_mutable.rs +++ /dev/null @@ -1,316 +0,0 @@ -// Fleece mutable-object API bindings, for Couchbase Lite document properties -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -use super::*; -use super::slice::*; -use super::c_api::*; -use super::fleece::*; - -use std::fmt; -use std::marker::PhantomData; -use std::ptr; - - - -pub enum CopyFlags { - Default = 0, // Shallow copy of mutable values - Deep = 1, // Deep copy of mutable values - CopyImmutables = 2, // Make copies of immutable values too - DeepCopyImmutables = 3, // The works -} - - -//////// MUTABLE ARRAY: - - -pub struct MutableArray { - pub(crate) _ref: FLMutableArray, -} - -impl MutableArray { - pub fn new() -> MutableArray { - unsafe { MutableArray{_ref: FLMutableArray_New()} } - } - - pub fn from_array(array: &Array) -> MutableArray { - MutableArray::from_array_(array, CopyFlags::Default) - } - - pub fn from_array_(array: &Array, flags: CopyFlags) -> MutableArray { - unsafe { MutableArray{_ref: FLArray_MutableCopy(array._ref, flags as u32)} } - } - - pub(crate) unsafe fn adopt(array: FLMutableArray) -> MutableArray { - FLValue_Retain(array as FLValue); - return MutableArray{_ref: array}; - } - - pub fn is_changed(&self) -> bool { - unsafe { FLMutableArray_IsChanged(self._ref) } - } - - pub fn at<'s>(&'s mut self, index: u32) -> Slot<'s> { - unsafe { Slot{_ref: FLMutableArray_Set(self._ref, index), _owner: PhantomData} } - } - - pub fn append<'s>(&'s mut self) -> Slot<'s> { - unsafe { Slot{_ref: FLMutableArray_Append(self._ref), _owner: PhantomData} } - } - - pub fn insert<'s>(&'s mut self, index: u32) { - unsafe { FLMutableArray_Insert(self._ref, index, 1) } - } - - pub fn remove(&mut self, index: u32) { - unsafe { FLMutableArray_Remove(self._ref, index, 1) } - } - - pub fn remove_all(&mut self) { - unsafe { FLMutableArray_Remove(self._ref, 0, self.count()) } - } -} - -// "Inherited" API: -impl MutableArray { - pub fn as_array(&self) -> Array { Array::wrap(self._ref, self) } - pub fn count(&self) -> u32 { self.as_array().count() } - pub fn empty(&self) -> bool { self.as_array().empty() } - pub fn get(&self, index: u32) -> Value { self.as_array().get(index) } - pub fn iter(&self) -> ArrayIterator { self.as_array().iter() } -} - -impl FleeceReference for MutableArray { - fn _fleece_ref(&self) -> FLValue { self._ref as FLValue } -} - -impl Clone for MutableArray{ - fn clone(&self) -> Self { - unsafe{ return MutableArray{_ref: FLValue_Retain(self._ref as FLValue) as FLMutableArray} } - } -} - -impl Drop for MutableArray { - fn drop(&mut self) { - unsafe{ FLValue_Release(self._ref as FLValue); } - } -} - -impl Default for MutableArray { - fn default() -> MutableArray { MutableArray{_ref: ptr::null_mut()} } -} - -impl PartialEq for MutableArray { - fn eq(&self, other: &Self) -> bool { self.as_value() == other.as_value() } -} - -impl Eq for MutableArray { } - -impl std::ops::Not for MutableArray { - type Output = bool; - fn not(self) -> bool {self._ref.is_null()} -} - -impl fmt::Debug for MutableArray { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("MutableArray") - .field("count", &self.count()) - .finish() - } -} - -impl fmt::Display for MutableArray { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - return f.write_str(&self.as_value().to_json()); - } -} - -impl<'a> IntoIterator for &'a MutableArray { - type Item = Value<'a>; - type IntoIter = ArrayIterator<'a>; - fn into_iter(self) -> Self::IntoIter { self.iter() } -} - - -// Mutable API additions for Array: -impl<'d> Array<'d> { - pub fn as_mutable(self) -> Option { - unsafe { - let md = FLArray_AsMutable(self._ref); - return if md.is_null() { None } else { Some(MutableArray::adopt(md)) }; - } - } - - pub fn mutable_copy(&self) -> MutableArray { - MutableArray::from_array(self) - } -} - - -//////// MUTABLE DICT: - - -pub struct MutableDict { - pub(crate) _ref: FLMutableDict, -} - -impl MutableDict { - pub fn new() -> MutableDict { - unsafe { MutableDict{_ref: FLMutableDict_New()} } - } - - pub fn from_dict(dict: &Dict) -> MutableDict { - MutableDict::from_dict_(dict, CopyFlags::Default) - } - - pub fn from_dict_(dict: &Dict, flags: CopyFlags) -> MutableDict { - unsafe { MutableDict{_ref: FLDict_MutableCopy(dict._ref, flags as u32)} } - } - - pub(crate) unsafe fn adopt(dict: FLMutableDict) -> MutableDict { - FLValue_Retain(dict as FLValue); - return MutableDict{_ref: dict}; - } - - pub fn is_changed(&self) -> bool { - unsafe { FLMutableDict_IsChanged(self._ref) } - } - - pub fn at<'s>(&'s mut self, key: &str) -> Slot<'s> { - unsafe { Slot{_ref: FLMutableDict_Set(self._ref, as_slice(key)), _owner: PhantomData} } - } - - pub fn remove(&mut self, key: &str) { - unsafe { FLMutableDict_Remove(self._ref, as_slice(key)) } - } - - pub fn remove_all(&mut self) { - unsafe { FLMutableDict_RemoveAll(self._ref) } - } -} - -// "Inherited" API: -impl MutableDict { - pub fn as_dict(&self) -> Dict { Dict::wrap(self._ref, self) } - pub fn count(&self) -> u32 { self.as_dict().count() } - pub fn empty(&self) -> bool { self.as_dict().empty() } - pub fn get(&self, key: &str) -> Value { self.as_dict().get(key) } - pub fn get_key(&self, key: &mut DictKey) -> Value { self.as_dict().get_key(key) } - pub fn iter(&self) -> DictIterator { self.as_dict().iter() } -} - -impl FleeceReference for MutableDict { - fn _fleece_ref(&self) -> FLValue { self._ref as FLValue } -} - -impl Clone for MutableDict{ - fn clone(&self) -> Self { - unsafe{ return MutableDict{_ref: FLValue_Retain(self._ref as FLValue) as FLMutableDict} } - } -} - -impl Drop for MutableDict { - fn drop(&mut self) { - unsafe{ FLValue_Release(self._ref as FLValue); } - } -} - -impl Default for MutableDict { - fn default() -> MutableDict { MutableDict{_ref: ptr::null_mut()} } -} - -impl PartialEq for MutableDict { - fn eq(&self, other: &Self) -> bool { self.as_value() == other.as_value() } -} - -impl Eq for MutableDict { } - -impl std::ops::Not for MutableDict { - type Output = bool; - fn not(self) -> bool {self._ref.is_null()} -} - -impl fmt::Debug for MutableDict { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("MutableDict") - .field("count", &self.count()) - .finish() - } -} - -impl fmt::Display for MutableDict { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - return f.write_str(&self.as_value().to_json()); - } -} - -impl<'a> IntoIterator for &'a MutableDict { - type Item = (&'a str, Value<'a>); - type IntoIter = DictIterator<'a>; - fn into_iter(self) -> Self::IntoIter { self.iter() } -} - - -// Mutable API for Dict: -impl<'d> Dict<'d> { - pub fn as_mutable(self) -> Option { - unsafe { - let md = FLDict_AsMutable(self._ref); - return if md.is_null() { None } else { Some(MutableDict::adopt(md)) }; - } - } - - pub fn mutable_copy(&self) -> MutableDict { - MutableDict::from_dict(self) - } -} - - -//////// SLOT: - - -/** A reference to an element of a MutableArray or MutableDict, - for the sole purpose of storing a value in it. */ -pub struct Slot<'s> { - pub(crate) _ref: FLSlot, - _owner: PhantomData<&'s mut MutableDict> -} - -impl<'s> Slot<'s> { - pub fn put_null(self) { unsafe { FLSlot_SetNull(self._ref) } } - - pub fn put_bool(self, value: bool) { unsafe { FLSlot_SetBool(self._ref, value) } } - - pub fn put_i64>(self, value: INT) { - unsafe { FLSlot_SetInt(self._ref, value.into()) } - } - - pub fn put_f64>(self, value: F) { - unsafe { FLSlot_SetDouble(self._ref, value.into()) } - } - - pub fn put_string>(self, value: STR) { - unsafe { FLSlot_SetString(self._ref, as_slice(value.as_ref())) } - } - - pub fn put_data>(self, value: DATA) { - unsafe { FLSlot_SetString(self._ref, bytes_as_slice(value.as_ref())) } - } - - pub fn put_value(self, value: &VALUE) { - unsafe { FLSlot_SetValue(self._ref, value._fleece_ref()) } - } -} diff --git a/bindings/rust/CouchbaseLite/src/fleece_tests.rs b/bindings/rust/CouchbaseLite/src/fleece_tests.rs deleted file mode 100644 index bd998bd8..00000000 --- a/bindings/rust/CouchbaseLite/src/fleece_tests.rs +++ /dev/null @@ -1,128 +0,0 @@ -// Unit tests for Fleece -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -#![cfg(test)] - -use crate::fleece::*; -use crate::fleece_mutable::*; - -#[test] -fn empty_values() { - let v = Value::default(); - assert_eq!(v.get_type(), ValueType::Undefined); - assert!(!v.is_type(ValueType::Bool)); - assert!(!v.is_number()); - assert!(!v.is_integer()); - assert_eq!(v.as_i64(), None); - assert!(!v.as_array()); - assert!(!v.as_dict()); - assert!(!v); - assert_eq!(v, Value::UNDEFINED); - assert!(v == v); -} - -#[test] -fn basic_values() { - let doc = Fleece::parse_json(r#"{"i":1234,"f":12.34,"a":[1, 2],"s":"Foo"}"#).unwrap(); - let dict = doc.as_dict(); - assert_eq!(dict.count(), 4); - - let i = dict.get("i"); - assert!(i.is_number()); - assert!(i.is_integer()); - assert_eq!(i.as_i64(), Some(1234)); - assert_eq!(i.as_i64_or_0(), 1234); - assert_eq!(i.as_f64(), Some(1234.0)); - assert_eq!(i.as_string(), None); - - let f = dict.get("f"); - assert!(f.is_number()); - assert!(!f.is_integer()); - assert_eq!(f.as_i64(), None); - assert_eq!(f.as_i64_or_0(), 12); - assert_eq!(f.as_f64(), Some(12.34)); - assert_eq!(f.as_string(), None); - - assert_eq!(dict.get("j"), Value::UNDEFINED); - - assert_eq!(dict.get("s").as_string(), Some("Foo")); - - let a = dict.get("a").as_array(); - assert!(a); - assert_eq!(a, a); - assert_eq!(a.count(), 2); - assert_eq!(a.get(0).as_i64(), Some(1)); - assert_eq!(a.get(1).as_i64(), Some(2)); - assert_eq!(a.get(2).as_i64(), None); - - assert_eq!(doc.root().to_json(), r#"{"a":[1,2],"f":12.34,"i":1234,"s":"Foo"}"#); - assert_eq!(format!("{}", doc.root()), r#"{"a":[1,2],"f":12.34,"i":1234,"s":"Foo"}"#); -} - -#[test] -fn nested_borrow_check() { - let v : Value; - let str : &str; - - let doc = Fleece::parse_json(r#"{"i":1234,"f":12.34,"a":[1, 2],"s":"Foo"}"#).unwrap(); - { - let dict = doc.as_dict(); - v = dict.get("a"); - str = dict.get("s").as_string().unwrap(); -} - // It's OK that `dict` has gone out of scope, because `v`s scope is `doc`, not `dict`. - println!("v = {:?}", v); - println!("str = {}", str); -} - -/* -// This test doesn't and shouldn't compile -- it tests that the borrow-checker will correctly -// prevent Fleece data from being used after its document has been freed. -#[test] -fn borrow_check() { - let v : Value; - let str : &str; - { - let doc = Fleece::parse_json(r#"{"i":1234,"f":12.34,"a":[1, 2],"s":"Foo"}"#).unwrap(); - let dict = doc.as_dict(); - v = dict.get("a"); - str = dict.get("s").as_string().unwrap(); - } - println!("v = {:?}", v); - println!("str = {}", str); -} -*/ - -#[test] -fn mutable_dict() { - let mut dict = MutableDict::new(); - assert_eq!(dict.count(), 0); - assert_eq!(dict.get("a"), Value::UNDEFINED); - - dict.at("i").put_i64(1234); - dict.at("s").put_string("Hello World!"); - - assert_eq!(format!("{}", dict), r#"{"i":1234,"s":"Hello World!"}"#); - - assert_eq!(dict.count(), 2); - assert_eq!(dict.get("i").as_i64(), Some(1234)); - assert_eq!(dict.get("s").as_string(), Some("Hello World!")); - assert!(!dict.get("?")); - - dict.remove("i"); - assert!(!dict.get("i")); -} diff --git a/bindings/rust/CouchbaseLite/src/lib.rs b/bindings/rust/CouchbaseLite/src/lib.rs deleted file mode 100644 index 61b9e552..00000000 --- a/bindings/rust/CouchbaseLite/src/lib.rs +++ /dev/null @@ -1,99 +0,0 @@ -// Couchbase Lite main module -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -//#![allow(unused_imports)] -//#![allow(dead_code)] - -#[macro_use] extern crate enum_primitive; - -pub mod blob; -pub mod database; -pub mod document; -pub mod error; -pub mod fleece; -pub mod fleece_mutable; -pub mod logging; -pub mod query; -pub mod replicator; - -mod slice; -mod c_api; - -mod fleece_tests; - -use self::c_api::*; - - -//////// RE-EXPORT: - - -pub use blob::*; -pub use database::*; -pub use document::*; -pub use error::*; -pub use fleece::*; -pub use fleece_mutable::*; -pub use query::*; -pub use replicator::*; - - -//////// TOP-LEVEL TYPES: - - -/// A time value for document expiration. Defined as milliseconds since the Unix epoch (1/1/1970.) -pub struct Timestamp(i64); - - -/// An opaque token representing a registered listener. -/// When this object is dropped, the listener function will not be called again. -pub struct ListenerToken { - _ref: *mut CBLListenerToken -} - - -impl Drop for ListenerToken { - fn drop(&mut self) { - unsafe { CBLListener_Remove(self._ref) } - } -} - - -//////// MISC. API FUNCTIONS - - -/** Returns the total number of Couchbase Lite objects. Useful for leak checking. */ -pub fn instance_count() -> usize { - unsafe { return CBL_InstanceCount() as usize } -} - -/** Logs the class and address of each Couchbase Lite object. Useful for leak checking. - @note May only be functional in debug builds of Couchbase Lite. */ -pub fn dump_instances() { - unsafe { CBL_DumpInstances() } -} - - -//////// REFCOUNT SUPPORT (INTERNAL) - - -pub(crate) unsafe fn retain(cbl_ref: *mut T) -> *mut T { - return CBL_Retain(cbl_ref as *mut CBLRefCounted) as *mut T -} - -pub(crate) unsafe fn release(cbl_ref: *mut T) { - CBL_Release(cbl_ref as *mut CBLRefCounted) -} diff --git a/bindings/rust/CouchbaseLite/src/logging.rs b/bindings/rust/CouchbaseLite/src/logging.rs deleted file mode 100644 index f1939486..00000000 --- a/bindings/rust/CouchbaseLite/src/logging.rs +++ /dev/null @@ -1,159 +0,0 @@ -// Couchbase Lite logging API -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -use super::slice::*; -use super::c_api::*; - -use enum_primitive::FromPrimitive; -use std::fmt; - - -enum_from_primitive! { - /** Logging domains: subsystems that generate log messages. */ - #[derive(Debug, Clone, Copy, PartialEq)] - pub enum Domain { - All, - Database, - Query, - Replicator, - Network - } -} - -enum_from_primitive! { - /** Levels of log messages. Higher values are more important/severe. - Each level includes the lower ones. */ - #[derive(Debug, Clone, Copy, PartialEq)] - pub enum Level { - Debug, - Verbose, - Info, - Warning, - Error, - None - } -} - - -pub type LogCallback = Option; - - -/** Sets the detail level of logging. - Only messages whose level is ≥ the given level will be logged to the console or callback. */ -pub fn set_level(level: Level, domain: Domain) { - unsafe { CBLLog_SetConsoleLevelOfDomain(domain as u8, level as u8) } -} - -/** Registers a function that will receive log messages. After this is called, messages will no - longer be written to stderr, but will be passed to this callback instead. */ -pub fn set_callback(callback: LogCallback) { - unsafe { - LOG_CALLBACK = callback; - if callback.is_some() { - CBLLog_SetCallback(Some(invoke_log_callback)); - } else { - CBLLog_SetCallback(None); - } - } -} - -/** Writes a log message. */ -pub fn write(domain: Domain, level: Level, message: &str) { - unsafe { - CBL_Log_s(domain as u8, level as u8, as_slice(message)); - - // CBL_Log doesn't invoke the callback, so do it manually: - if let Some(callback) = LOG_CALLBACK { - if CBLLog_WillLogToConsole(domain as u8, level as u8) { - callback(domain, level, message); - } - } - } -} - -/** Writes a log message using the given format arguments. */ -pub fn write_args(domain: Domain, level: Level, args: fmt::Arguments) { - unsafe { - if CBLLog_WillLogToConsole(domain as u8, level as u8) { - write(domain, level, &format!("{:?}", args)); - } - } -} - - -//////// LOGGING MACROS: - - -/// A macro that writes a formatted Error-level log message. -#[macro_export] -macro_rules! error { - ($($arg:tt)*) => ($crate::logging::write_args( - $crate::logging::Domain::All, $crate::logging::Level::Error, - format_args!($($arg)*))); -} - -/// A macro that writes a formatted Warning-level log message. -#[macro_export] -macro_rules! warn { - ($($arg:tt)*) => ($crate::logging::write_args( - $crate::logging::Domain::All, $crate::logging::Level::Warning, - format_args!($($arg)*))); -} - -/// A macro that writes a formatted Info-level log message. -#[macro_export] -macro_rules! info { - ($($arg:tt)*) => ($crate::logging::write_args( - $crate::logging::Domain::All, $crate::logging::Level::Info, - format_args!($($arg)*))); -} - -/// A macro that writes a formatted Verbose-level log message. -#[macro_export] -macro_rules! verbose { - ($($arg:tt)*) => ($crate::logging::write_args( - $crate::logging::Domain::All, $crate::logging::Level::Verbose, - format_args!($($arg)*))); -} - -/// A macro that writes a formatted Debug-level log message. -#[macro_export] -macro_rules! debug { - ($($arg:tt)*) => ($crate::logging::write_args( - $crate::logging::Domain::All, $crate::logging::Level::Debug, - format_args!($($arg)*))); -} - - -//////// INTERNALS: - - -static mut LOG_CALLBACK : LogCallback = Some(default_callback); - -fn default_callback(_domain: Domain, _level: Level, msg: &str) { - println!("CBL: {}", msg); -} - -unsafe extern "C" fn invoke_log_callback(c_domain: CBLLogDomain, c_level: CBLLogLevel, - msg: *const ::std::os::raw::c_char) -{ - let domain = Domain::from_u8(c_domain).unwrap(); - let level = Level::from_u8(c_level).unwrap(); - if let Some(cb) = LOG_CALLBACK { - cb(domain, level, &to_str(msg)); - } -} diff --git a/bindings/rust/CouchbaseLite/src/main.rs b/bindings/rust/CouchbaseLite/src/main.rs deleted file mode 100644 index 41221e07..00000000 --- a/bindings/rust/CouchbaseLite/src/main.rs +++ /dev/null @@ -1,47 +0,0 @@ -// A very simple program using Couchbase Lite -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -extern crate couchbase_lite; -extern crate tempdir; - -use couchbase_lite::*; -use tempdir::TempDir; - - -fn main() { - // Create a new database in a temporary directory: - let tmp_dir = TempDir::new("cbl_rust").expect("create temp dir"); - let cfg = DatabaseConfiguration{directory: tmp_dir.path(), flags: CREATE}; - let mut db = Database::open("main_db", Some(cfg)).expect("open db"); - - // Create and save a new document: - { - //logging::set_level(logging::Level::Info, logging::Domain::All); - let mut doc = Document::new_with_id("foo"); - let mut props = doc.mutable_properties(); - props.at("i").put_i64(1234); - props.at("s").put_string("Hello World!"); - - db.save_document(&mut doc, ConcurrencyControl::FailOnConflict).expect("save"); - } - // Reload the document and verify its properties: - { - let doc = db.get_document("foo").expect("reload document"); - let props = doc.properties(); - assert_eq!(props.to_json(), r#"{"i":1234,"s":"Hello World!"}"#); - } -} diff --git a/bindings/rust/CouchbaseLite/src/query.rs b/bindings/rust/CouchbaseLite/src/query.rs deleted file mode 100644 index 56f87cd5..00000000 --- a/bindings/rust/CouchbaseLite/src/query.rs +++ /dev/null @@ -1,212 +0,0 @@ -// Couchbase Lite query API -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -use super::*; -use super::slice::*; -use super::c_api::*; - -use std::marker::PhantomData; -use std::os::raw::c_uint; - - -/** Query languages. */ -pub enum QueryLanguage { - JSON, // JSON query schema: github.com/couchbase/couchbase-lite-core/wiki/JSON-Query-Schema - N1QL, // N1QL syntax: docs.couchbase.com/server/6.0/n1ql/n1ql-language-reference/index.html -} - - -/** A compiled database query. */ -pub struct Query { - _ref: *mut CBLQuery -} - -impl Query { - /** Creates a new query by compiling the input string. - This is fast, but not instantaneous. If you need to run the same query many times, keep the - `Query` around instead of compiling it each time. If you need to run related queries - with only some values different, create one query with placeholder parameter(s), and substitute - the desired value(s) with `set_parameters` before each time you run the query. */ - pub fn new(db: &Database, language: QueryLanguage, str: &str) -> Result { - unsafe { - let mut pos: i32 = 0; - let mut err = CBLError::default(); - let q = CBLQuery_New_s(db._ref, language as CBLQueryLanguage, as_slice(str), - &mut pos, &mut err); - if q.is_null() { - // TODO: Return the error pos somehow - return failure(err); - } - return Ok(Query{_ref: q}); - } - } - - /** Assigns values to the query's parameters. - These values will be substited for those parameters whenever the query is executed, - until they are next assigned. - - Parameters are specified in the query source as - e.g. `$PARAM` (N1QL) or `["$PARAM"]` (JSON). In this example, the `parameters` dictionary - to this call should have a key `PARAM` that maps to the value of the parameter. */ - pub fn set_parameters(&self, parameters: MutableDict) { - unsafe { - CBLQuery_SetParameters(self._ref, parameters._ref); - } - } - - /** Returns the query's current parameter bindings, if any. */ - pub fn parameters(&self) -> Dict { - unsafe { return Dict{_ref: CBLQuery_Parameters(self._ref), _owner: PhantomData}; } - } - - /** Assigns values to the query's parameters, from JSON data. - See `set_parameters` for details. */ - pub fn set_parameters_json(&self, json: &str) { - unsafe { CBLQuery_SetParametersAsJSON_s(self._ref, as_slice(json)); } - } - - /** Returns information about the query, including the translated SQLite form, and the search - strategy. You can use this to help optimize the query: the word `SCAN` in the strategy - indicates a linear scan of the entire database, which should be avoided by adding an index. - The strategy will also show which index(es), if any, are used. */ - pub fn explain(&self) -> String { - unsafe { CBLQuery_Explain(self._ref).to_string().unwrap() } - } - - /** Runs the query, returning the results as a `ResultSet` object, which is an iterator - of `Row` objects, each of which has column values. */ - pub fn execute(&self) -> Result { - unsafe { - let mut err = CBLError::default(); - let r = CBLQuery_Execute(self._ref, &mut err); - if r.is_null() { - return failure(err); - } - return Ok(ResultSet{_ref: r}); - } - } - - /** Returns the number of columns in each result. - This comes directly from the number of "SELECT..." values in the query string. */ - pub fn column_count(&self) -> usize { - unsafe { CBLQuery_ColumnCount(self._ref) as usize } - } - - /** Returns the name of a column in the result. - The column name is based on its expression in the `SELECT...` or `WHAT:` section of the - query. A column that returns a property or property path will be named after that property. - A column that returns an expression will have an automatically-generated name like `$1`. - To give a column a custom name, use the `AS` syntax in the query. - Every column is guaranteed to have a unique name. */ - pub fn column_name(&self, col: usize) -> Option<&str> { - unsafe { CBLQuery_ColumnName(self._ref, col as u32).as_str() } - } - - /** Returns the column names as a Vec. */ - pub fn column_names(&self) -> Vec<&str> { - (0..self.column_count()).map(|i| self.column_name(i).unwrap()).collect() - } -} - -impl Drop for Query { - fn drop(&mut self) { - unsafe { release(self._ref); } - } -} - -impl Clone for Query { - fn clone(&self) -> Self { - unsafe { Query{_ref: retain(self._ref)} } - } -} - - -//////// RESULT SET: - - -/** An iterator over the rows resulting from running a query. */ -pub struct ResultSet { - _ref: *mut CBLResultSet -} - -impl<'r> Iterator for &'r ResultSet { - type Item = Row<'r>; - - fn next(&mut self) -> Option> { - unsafe { - if !CBLResultSet_Next(self._ref) { - return None; - } - return Some(Row{results: &self}) - } - } -} - -impl Drop for ResultSet { - fn drop(&mut self) { - unsafe { release(self._ref); } - } -} - - -//////// ROW: - - -/** A single result row from a Query. */ -pub struct Row<'r> { - results: &'r ResultSet -} - -impl<'r> Row<'r> { - /** Returns the value of a column, given its (zero-based) index. */ - pub fn get(&self, index: isize) -> Value<'r> { - unsafe { Value{_ref: CBLResultSet_ValueAtIndex(self.results._ref, index as c_uint), - _owner: PhantomData} } - } - - /** Returns the value of a column, given its name. */ - pub fn get_key(&self, key: &str) -> Value<'r> { - unsafe { Value{_ref: CBLResultSet_ValueForKey_s(self.results._ref, as_slice(key)), - _owner: PhantomData} } - } - - /** Returns the number of columns. (This is the same as `Query`::column_count.) */ - pub fn column_count(&self) -> isize { - unsafe { - let query = CBLResultSet_GetQuery(self.results._ref); - return CBLQuery_ColumnCount(query) as isize; - } - } - - /** Returns the name of a column. */ - pub fn column_name(&self, col: isize) -> Option<&str> { - unsafe { - let query = CBLResultSet_GetQuery(self.results._ref); - return CBLQuery_ColumnName(query, col as c_uint).as_str(); - } - } - - /** Returns all of the columns as a Fleece array. */ - pub fn as_array(&self) -> Array { - unsafe { Array{_ref: CBLResultSet_RowArray(self.results._ref), _owner: PhantomData} } - } - - /** Returns all of the columns as a Fleece dictionary. */ - pub fn as_dict(&self) -> Dict { - unsafe { Dict{_ref: CBLResultSet_RowDict(self.results._ref), _owner: PhantomData} } - } -} diff --git a/bindings/rust/CouchbaseLite/src/replicator.rs b/bindings/rust/CouchbaseLite/src/replicator.rs deleted file mode 100644 index 5dd85033..00000000 --- a/bindings/rust/CouchbaseLite/src/replicator.rs +++ /dev/null @@ -1,242 +0,0 @@ -// Couchbase Lite replicator API -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -use super::*; -use super::c_api::*; - -use std::collections::HashMap; -use std::collections::HashSet; - - -// WARNING: THIS API IS UNIMPLEMENTED SO FAR - - -//======== CONFIGURATION - - -/** Represents the location of a database to replicate with. */ -pub enum Endpoint<'e> { - WithURL (String), - WithLocalDB (&'e Database) -} - - -pub enum Authenticator<'a> { - None, - Basic {username: &'a str, password: &'a str}, - Session {session_id: &'a str}, - Cookie {name: &'a str, value: &'a str} -} - - -/** Direction of replication: push, pull, or both. */ -#[derive(Debug)] -pub enum ReplicatorType { PushAndPull, Push, Pull } - - -/** Types of proxy servers, for CBLProxySettings. */ -#[derive(Debug)] -pub enum ProxyType { HTTP, HTTPS } - -/** Proxy settings for the replicator. */ -pub struct ProxySettings<'p> { - pub proxy_type: ProxyType, // Type of proxy - pub hostname: &'p str, // Proxy server hostname or IP address - pub port: u16, // Proxy server port - pub username: Option<&'p str>, // Username for proxy auth - pub password: Option<&'p str> // Password for proxy auth -} - - -/** A callback that can decide whether a particular document should be pushed or pulled. */ -pub type ReplicationFilter = fn(document: &Document, - is_deleted: bool) -> bool; - -/** Conflict-resolution callback for use in replications. This callback will be invoked - when the replicator finds a newer server-side revision of a document that also has local - changes. The local and remote changes must be resolved before the document can be pushed - to the server. */ -pub type ConflictResolver = fn(document_id: &str, - local_document: Option, - remote_document: Option) -> Document; - - -/** The configuration of a replicator. */ -pub struct ReplicatorConfiguration<'c> { - pub database: &'c Database, // The database to replicate - pub endpoint: Endpoint<'c>, // The address of the other database to replicate with - pub replicator_type: ReplicatorType, // Push, pull or both - pub continuous: bool, // Continuous replication? - pub authenticator: Authenticator<'c>, // Authentication credentials, if needed - pub proxy: Option>, // HTTP client proxy settings - pub headers: Option>, // Extra HTTP headers to add to the WebSocket request - pub pinned_server_certificate: Option>, // An X.509 cert to "pin" TLS connections to (PEM or DER) - pub trusted_root_certificates: Option>, // Set of anchor certs (PEM format) - pub channels: Option>, // Optional set of channels to pull from - pub document_ids: Option>, // Optional set of document IDs to replicate - pub push_filter: ReplicationFilter, // Optional callback to filter which docs are pushed - pub pull_filter: ReplicationFilter, // Optional callback to validate incoming docs - pub conflict_resolver: ConflictResolver, // Optional conflict-resolver callback -} - - -//======== LIFECYCLE - -/** A background task that syncs a \ref Database with a remote server or peer. */ -pub struct Replicator { - _ref: *mut CBLReplicator -} - -impl Replicator { - /** Creates a replicator with the given configuration. */ - pub fn new(_config: ReplicatorConfiguration) -> Result { - todo!() - } - - /** Returns the configuration of an existing replicator. */ - pub fn config(&self) -> ReplicatorConfiguration { - todo!() - } - - /** Instructs the replicator to ignore existing checkpoints the next time it runs. - This will cause it to scan through all the documents on the remote database, which takes - a lot longer, but it can resolve problems with missing documents if the client and - server have gotten out of sync somehow. */ - pub fn reset_checkpoint(&mut self) { - todo!() - } - - /** Starts a replicator, asynchronously. Does nothing if it's already started. */ - pub fn start(&mut self) { - todo!() - } - - /** Stops a running replicator, asynchronously. Does nothing if it's not already started. - The replicator will call your \ref CBLReplicatorChangeListener with an activity level of - \ref kCBLReplicatorStopped after it stops. Until then, consider it still active. */ - pub fn stop(&mut self) { - todo!() - } - - /** Informs the replicator whether it's considered possible to reach the remote host with - the current network configuration. The default value is true. This only affects the - replicator's behavior while it's in the Offline state: - * Setting it to false will cancel any pending retry and prevent future automatic retries. - * Setting it back to true will initiate an immediate retry.*/ - pub fn set_host_reachable(&mut self, _reachable: bool) { - todo!() - } - - /** Puts the replicator in or out of "suspended" state. The default is false. - * Setting suspended=true causes the replicator to disconnect and enter Offline state; - it will not attempt to reconnect while it's suspended. - * Setting suspended=false causes the replicator to attempt to reconnect, _if_ it was - connected when suspended, and is still in Offline state. */ - pub fn set_suspended(&mut self, _suspended: bool) { - todo!() - } - -} - -impl Drop for Replicator { - fn drop(&mut self) { unsafe { CBL_Release(self._ref as *mut CBLRefCounted) } } -} - - -//======== STATUS AND PROGRESS - - -/** The possible states a replicator can be in during its lifecycle. */ -#[derive(Debug)] -pub enum ReplicatorActivityLevel { - Stopped, // The replicator is unstarted, finished, or hit a fatal error. - Offline, // The replicator is offline, as the remote host is unreachable. - Connecting, // The replicator is connecting to the remote host. - Idle, // The replicator is inactive, waiting for changes to sync. - Busy // The replicator is actively transferring data. -} - -/** The current progress status of a Replicator. The `fraction_complete` ranges from 0.0 to 1.0 as - replication progresses. The value is very approximate and may bounce around during replication; - making it more accurate would require slowing down the replicator and incurring more load on the - server. It's fine to use in a progress bar, though. */ -pub struct ReplicatorProgress { - pub fraction_complete: f32, // Very-approximate completion, from 0.0 to 1.0 - pub document_count: u64 // Number of documents transferred so far -} - -/** A replicator's current status. */ -pub struct ReplicatorStatus { - pub activity: ReplicatorActivityLevel, // Current state - pub progress: ReplicatorProgress, // Approximate fraction complete - pub error: Result<()> // Error, if any -} - -/** A callback that notifies you when the replicator's status changes. */ -pub type ReplicatorChangeListener = fn(&Replicator, ReplicatorStatus); - -/** Flags describing a replicated document. */ -pub static DELETED : u32 = kCBLDocumentFlagsDeleted; -pub static ACCESS_REMOVED : u32 = kCBLDocumentFlagsAccessRemoved; - -/** Information about a document that's been pushed or pulled. */ -pub struct ReplicatedDocument<'d> { - pub id: &'d str, // The document ID - pub flags: u32, // Indicates whether the document was deleted or removed - pub error: Result<()> // Error, if document failed to replicate -} - -/** Direction of document transfer. */ -#[derive(Debug)] -pub enum Direction {Pulled, Pushed } - -/** A callback that notifies you when documents are replicated. */ -pub type ReplicatedDocumentListener = fn(&Replicator, Direction, Vec); - -impl Replicator { - - /** Returns the replicator's current status. */ - pub fn status(&self) -> ReplicatorStatus { - todo!() - } - - /** Indicates which documents have local changes that have not yet been pushed to the server - by this replicator. This is of course a snapshot, that will go out of date as the replicator - makes progress and/or documents are saved locally. */ - pub fn pending_document_ids(&self) -> Result> { - todo!() - } - - /** Indicates whether the document with the given ID has local changes that have not yet been - pushed to the server by this replicator. - - This is equivalent to, but faster than, calling \ref pending_document_ids and - checking whether the result contains \p docID. See that function's documentation for details. */ - pub fn is_document_pending(_doc_id: &str) -> Result { - todo!() - } - - /** Adds a listener that will be called when the replicator's status changes. */ - pub fn add_change_listener(&mut self, _listener: ReplicatorChangeListener) -> ListenerToken { - todo!() - } - - /** Adds a listener that will be called when documents are replicated. */ - pub fn add_document_listener(&mut self, _listener: ReplicatedDocumentListener) -> ListenerToken { - todo!() - } -} diff --git a/bindings/rust/CouchbaseLite/src/slice.rs b/bindings/rust/CouchbaseLite/src/slice.rs deleted file mode 100644 index fc08c641..00000000 --- a/bindings/rust/CouchbaseLite/src/slice.rs +++ /dev/null @@ -1,130 +0,0 @@ -// Internal API for working with FLSlice, FLSliceResult, and C strings -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// - -use super::c_api::*; - -use std::borrow::Cow; -use std::ffi::c_void; -use std::ffi::CStr; -use std::ptr; -use std::str; - - -//////// SLICES - - -pub const NULL_SLICE : FLSlice = FLSlice{buf: ptr::null(), size: 0}; - - -pub fn as_slice(s: &str) -> FLSlice { - return FLSlice{buf: s.as_ptr() as *const c_void, - size: s.len() as u64}; -} - -pub fn bytes_as_slice(s: &[u8]) -> FLSlice { - return FLSlice{buf: s.as_ptr() as *const c_void, - size: s.len() as u64}; -} - -impl FLSlice { - // A slice may be null, so in Rust terms it's an Option. - - pub unsafe fn as_byte_array<'a>(&self) -> Option<&'a [u8]> { - if !self { return None } - return Some(std::slice::from_raw_parts(self.buf as *const u8, self.size as usize)) - } - pub unsafe fn as_str<'a>(&self) -> Option<&'a str> { - match self.as_byte_array() { - None => None, - Some(b) => { str::from_utf8(b).ok() } - } - } - pub unsafe fn to_string(&self) -> Option { - return self.as_str().map(|s| s.to_string()); - } - - pub unsafe fn to_vec(&self) -> Option> { - return self.as_byte_array().map(|a| a.to_owned()); - } - - pub fn map(&self, f : F) -> Option - where F: Fn(&FLSlice)->T - { - if !self {None} else {Some(f(self))} - } -} - -impl std::ops::Not for &FLSlice { - type Output = bool; - fn not(self) -> bool {self.buf.is_null()} -} - -impl std::ops::Not for FLSlice { - type Output = bool; - fn not(self) -> bool {self.buf.is_null()} -} - -impl FLSliceResult { - pub fn as_slice(&self) -> FLSlice { - return FLSlice{buf: self.buf, size: self.size}; - } - - // pub unsafe fn retain(&mut self) { - // _FLBuf_Retain(self.buf); - // } - - // It's not possible to implement Drop for FLSliceResult, because the generated interface - // makes it implement Copy. So it has to be released by hand. - pub unsafe fn release(&mut self) { - _FLBuf_Release(self.buf); - } - - // Consumes & releases self - pub unsafe fn to_string(mut self) -> Option { - let str = self.as_slice().to_string(); - self.release(); - return str; - } - - // Consumes & releases self - pub unsafe fn to_vec(mut self) -> Option> { - let vec = self.as_slice().to_vec(); - self.release(); - return vec; - } -} - - -//////// C STRINGS - - -// Convenience to convert a raw `char*` to an unowned `&str` -pub unsafe fn to_str<'a>(cstr: *const ::std::os::raw::c_char) -> Cow<'a, str> { - return CStr::from_ptr(cstr).to_string_lossy() -} - - -// Convenience to convert a raw `char*` to an owned String -pub unsafe fn to_string(cstr: *const ::std::os::raw::c_char) -> String { - return to_str(cstr).to_string(); -} - -/* -pub(crate) unsafe fn free_cstr(cstr: *const ::std::os::raw::c_char) { - todo!(); // Implement this by calling `free()` -} -*/ diff --git a/bindings/rust/CouchbaseLite/tests/simple_tests.rs b/bindings/rust/CouchbaseLite/tests/simple_tests.rs deleted file mode 100644 index ecee7fd0..00000000 --- a/bindings/rust/CouchbaseLite/tests/simple_tests.rs +++ /dev/null @@ -1,189 +0,0 @@ -// Couchbase Lite unit tests -// -// Copyright (c) 2020 Couchbase, Inc All rights reserved. -// -// 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. -// -#![allow(unused_imports)] - -extern crate couchbase_lite; -extern crate tempdir; - -use couchbase_lite::*; -use tempdir::TempDir; - -// Enables check for leaks of native CBL objects after `with_db()` finishes. -// WARNING: These checks only work if one test method runs at a time, i.e. testing is single -// threaded. Run as `cargo test -- --test-threads=1` or you'll get false positives. -const LEAK_CHECKS : bool = true; - -const DB_NAME : &str = "test_db"; - -const LEVEL_PREFIX : [&str;5] = ["((", "_", "", "WARNING: ", "***ERROR: "]; -const LEVEL_SUFFIX : [&str;5] = ["))", "_", "", "", " ***"]; - - -fn logger(domain: logging::Domain, level: logging::Level, message: &str) { - // Log to stdout, not stderr, so that `cargo test` will buffer the output. - let i = level as usize; - println!("CBL {:?}: {}{}{}", - domain, LEVEL_PREFIX[i], message, LEVEL_SUFFIX[i]) - -} - -fn init_logging() { - logging::set_callback(Some(logger)); -} - -// Test wrapper function -- takes care of creating and deleting the database. -fn with_db(f: F) - where F: Fn(&mut Database) -{ - init_logging(); - - let start_inst_count = instance_count() as isize; - let tmp_dir = TempDir::new("cbl_rust").expect("create temp dir"); - let cfg = DatabaseConfiguration{directory: tmp_dir.path(), flags: CREATE}; - let mut db = Database::open(DB_NAME, Some(cfg)).expect("open db"); - assert!(Database::exists(DB_NAME, tmp_dir.path())); - - f(&mut db); - - drop(db); - if LEAK_CHECKS && instance_count() as isize > start_inst_count { - dump_instances(); - panic!("Native object leak: {} objects, was {}", - instance_count(), start_inst_count); - } -} - -fn add_doc(db: &mut Database, id: &str, i: i64, s: &str) { - let mut doc = Document::new_with_id(id); - let mut props = doc.mutable_properties(); - props.at("i").put_i64(i); - props.at("s").put_string(s); - db.save_document(&mut doc, ConcurrencyControl::FailOnConflict).expect("save"); -} - - -//////// TESTS: - -#[test] -fn db_properties() { - with_db(|db| { - assert_eq!(db.name(), DB_NAME); - assert_eq!(db.count(), 0); - }); -} - -#[test] -fn create_document() { - with_db(|_db| { - let doc = Document::new_with_id("foo"); - assert_eq!(doc.id(), "foo"); - assert_eq!(doc.sequence(), 0); - assert!(doc.properties()); - assert_eq!(doc.properties().count(), 0); - }); -} - -#[test] -fn save_document() { - with_db(|db| { - { - logging::set_level(logging::Level::Info, logging::Domain::All); - let mut doc = Document::new_with_id("foo"); - let mut props = doc.mutable_properties(); - props.at("i").put_i64(1234); - props.at("s").put_string("Hello World!"); - - db.save_document(&mut doc, ConcurrencyControl::FailOnConflict).expect("save"); - } - { - let doc = db.get_document("foo").expect("reload document"); - let props = doc.properties(); - verbose!("Blah blah blah"); - info!("Interesting: {} = {}", 2+2, 4); - warn!("Some warning"); - error!("Oh no, props = {}", props); - assert_eq!(props.to_json(), r#"{"i":1234,"s":"Hello World!"}"#); - } - }); -} - -#[test] -fn query() { - with_db(|db| { - add_doc(db, "doc-1", 1, "one"); - add_doc(db, "doc-2", 2, "two"); - add_doc(db, "doc-3", 3, "three"); - - let query = Query::new(db, QueryLanguage::N1QL, "select i, s where i > 1 order by i").expect("create query"); - assert_eq!(query.column_count(), 2); - assert_eq!(query.column_name(0), Some("i")); - assert_eq!(query.column_name(1), Some("s")); - - // Step through the iterator manually: - let results = query.execute().expect("execute"); - let mut row = (&results).next().unwrap(); //FIXME: Do something about the (&results). requirement - let mut i = row.get(0).as_i64().unwrap(); - let mut s = row.get(1).as_string().unwrap(); - assert_eq!(i, 2); - assert_eq!(s, "two"); - assert_eq!(row.as_dict().to_json(), r#"{"i":2,"s":"two"}"#); - - row = (&results).next().unwrap(); - i = row.get(0).as_i64().unwrap(); - s = row.get(1).as_string().unwrap(); - assert_eq!(i, 3); - assert_eq!(s, "three"); - assert_eq!(row.as_dict().to_json(), r#"{"i":3,"s":"three"}"#); - - assert!((&results).next().is_none()); - - // Now try a for...in loop: - let mut n = 0; - for row in &query.execute().expect("execute") { - match n { - 0 => { - assert_eq!(row.as_array().to_json(), r#"[2,"two"]"#); - assert_eq!(row.as_dict().to_json(), r#"{"i":2,"s":"two"}"#); - }, - 1 => { - assert_eq!(row.as_array().to_json(), r#"[3,"three"]"#); - assert_eq!(row.as_dict().to_json(), r#"{"i":3,"s":"three"}"#); - }, - _ => {panic!("Too many rows ({})", n);} - } - n += 1; - - } - assert_eq!(n, 2); - }); -} - - -/* -// This test doesn't and shouldn't compile -- it tests that the borrow-checker will correctly -// prevent Fleece data from being used after its document has been freed. -#[test] -fn document_borrow_check() { - let mut db = Database::open(DB_NAME, None).expect("open db"); - let v : Value; - { - let doc = db.get_document("foo").expect("get doc"); - v = doc.properties().get("a"); - } - println!("v = {:?}", v); -} -*/ diff --git a/bindings/rust/CouchbaseLite/wrapper.h b/bindings/rust/CouchbaseLite/wrapper.h deleted file mode 100644 index 10e9af61..00000000 --- a/bindings/rust/CouchbaseLite/wrapper.h +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../../include/cbl/CouchbaseLite.h" -#include "../../../src/CBLPrivate.h" diff --git a/bindings/rust/README.md b/bindings/rust/README.md deleted file mode 100644 index 16bf1ebb..00000000 --- a/bindings/rust/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# Rust Language Bindings For Couchbase Lite - -10 May 2020 - -The `CouchbaseLite` subdirectory of this directory is a Cargo package containing a [Couchbase -Lite][CBL] API binding for the [Rust language][RUST]. - -It's still in early development. It's incomplete, has only had some informal testing, and that -only on macOS. Also I (Jens) am a newbie at Rust and may not be doing things the write way. -Feedback gratefully accepted. - -## Prerequisites - -In addition to Rust, you'll need to install [bindgen][BINDGEN], which generates Rust FFI APIs -from C headers. Installation instructions are [here][BINDGEN_INSTALL] -- the main thing you'll need -to do is install Clang. - -## Building - -**_"Some assembly required..."_** - -You first need to build Couchbase Lite For C (the root of this repo) with CMake, by running the -`build.sh` script in the repo root directory. That will produce the shared library. - - $ cd ../.. - $ ./build.sh - -After that, go to the `CouchbaseLite` package directory and fix the hardcoded path I left in the -`build.rs` file: it's the value of `DEFAULT_LIBCLANG_PATH` at line 32. You'll need to find out where -your LLVM installation directory is, and set this string constant to the path to its `lib` -subdirectory. - - $ cd bindings/rust/CouchbaseLite/ - $ my_favorite_editor build.rs - -Now that this is set up, you can build normally with Cargo: - - $ cargo build - -**Unit tests must be run single-threaded.** This is because each test case checks for leaks by -counting the number of extant Couchbase Lite objects before and after it runs, and failing if the -number increases. This works only if a single test runs at a time. - - $ cargo test -- --test-threads 1 - -The library itself has no thread-safety problems; if you want to run the tests multi-threaded, just -edit `tests/simple_tests.rs` and change the value of `LEAK_CHECKS` to `false`. - -## Learning - -I've copied the doc-comments from the C API into the Rust files. But Couchbase Lite is fairly -complex, so if you're not already familiar with it, you'll want to start by reading through -the [official documentation][CBLDOCS]. - -The Rust API is mostly method-for-method compatible with the languages documented there, except -down at the document property level (dictionaries, arrays, etc.) where I haven't yet written -compatible bindings. For those APIs you can check out the document "[Using Fleece][FLEECE]". - - -[RUST]: https://www.rust-lang.org -[CBL]: https://www.couchbase.com/products/lite -[CBLDOCS]: https://docs.couchbase.com/couchbase-lite/current/introduction.html -[FLEECE]: https://github.com/couchbaselabs/fleece/wiki/Using-Fleece -[BINDGEN]: https://rust-lang.github.io/rust-bindgen/ -[BINDGEN_INSTALL]: https://rust-lang.github.io/rust-bindgen/requirements.html diff --git a/bindings/rust/rust.sublime-project b/bindings/rust/rust.sublime-project deleted file mode 100644 index 8cae4287..00000000 --- a/bindings/rust/rust.sublime-project +++ /dev/null @@ -1,24 +0,0 @@ -{ - "folders": [ - { - "path": "CouchbaseLite/src" - }, - { - "path": "CouchbaseLite/tests" - }, - { - "path": "CouchbaseLite", - "name": "Crate", - "file_include_patterns": ["*.toml", "*.h", "bindings.rs"], - "folder_include_patterns": ["target", "debug", "build", "out", "couchbase_lite-*"] - } - ], - "settings": { - "tab_size": 4, - "translate_tabs_to_spaces": true, - "rulers": [100], - "trim_trailing_white_space_on_save": true, - "ensure_newline_at_eof_on_save": true, - "default_line_ending": "unix", - }, -} diff --git a/cmake/generate_edition.cmake b/cmake/generate_edition.cmake index 6beea9eb..1483292f 100644 --- a/cmake/generate_edition.cmake +++ b/cmake/generate_edition.cmake @@ -46,6 +46,7 @@ macro(generate_edition) endif() if(DEFINED ENV{BLD_NUM}) + message(VERBOSE "Using BLD_NUM:$ENV{BLD_NUM} from environment variable") set(CouchbaseLite_C_BUILD $ENV{BLD_NUM}) else() message(WARNING "No BLD_NUM set, defaulting to 0...") @@ -54,7 +55,7 @@ macro(generate_edition) endif() math(EXPR CouchbaseLite_C_VERNUM "${CouchbaseLite_C_VERSION_MAJOR} * 1000000 + ${CouchbaseLite_C_VERSION_MINOR} * 1000 + ${CouchbaseLite_C_VERSION_PATCH}") - string(TIMESTAMP CouchbaseLite_C_SOURCE_ID) + string(TIMESTAMP CouchbaseLite_C_BUILD_TIMESTAMP UTC) find_package(Git) if(Git_FOUND) @@ -89,9 +90,9 @@ macro(generate_edition) string(PREPEND HASH "${EE_HASH}+") endif() - string(APPEND CouchbaseLite_C_SOURCE_ID " ${HASH}") + set(CouchbaseLite_C_SOURCE_ID "${HASH}") else() - string(APPEND CouchbaseLite_C_SOURCE_ID " ") + set(CouchbaseLite_C_SOURCE_ID "") endif() configure_file( diff --git a/cmake/platform_apple.cmake b/cmake/platform_apple.cmake index 98d3eab2..47fdb4d5 100644 --- a/cmake/platform_apple.cmake +++ b/cmake/platform_apple.cmake @@ -8,6 +8,7 @@ function(set_platform_source_files) set( ${PLATFORM_RESULT} src/CBLDatabase+Apple.mm + src/CBLUserAgent.mm PARENT_SCOPE ) endfunction() diff --git a/docs/C/html/_base_8h.html b/docs/C/html/_base_8h.html index f8ed88b6..7b5f4668 100644 --- a/docs/C/html/_base_8h.html +++ b/docs/C/html/_base_8h.html @@ -1,9 +1,9 @@ - + - - + + Couchbase Lite C: vendor/couchbase-lite-core/vendor/fleece/API/fleece/Base.h File Reference @@ -19,8 +19,8 @@
- - +
+
Couchbase Lite C
Couchbase Lite C API
@@ -30,21 +30,22 @@
- + +/* @license-end */ +
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+