Lot's of changes

This commit is contained in:
Peter 2015-07-08 17:16:47 +03:00
parent 4630a223b2
commit cc75497a0c
18 changed files with 161703 additions and 21 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "submodules/sqlite.swift"]
path = submodules/sqlite.swift
url = https://github.com/stephencelis/SQLite.swift.git

View File

@ -7,9 +7,35 @@
objects = {
/* Begin PBXBuildFile section */
D003E4E61B38DBDB00C22CBC /* MessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D003E4E51B38DBDB00C22CBC /* MessageView.swift */; };
D044E15E1B2ACB9C001EE087 /* CodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D044E15D1B2ACB9C001EE087 /* CodingTests.swift */; };
D044E1631B2AD677001EE087 /* MurMurHash32.m in Sources */ = {isa = PBXBuildFile; fileRef = D044E1621B2AD677001EE087 /* MurMurHash32.m */; };
D044E1641B2AD718001EE087 /* MurMurHash32.h in Headers */ = {isa = PBXBuildFile; fileRef = D044E1611B2AD667001EE087 /* MurMurHash32.h */; settings = {ATTRIBUTES = (Public, ); }; };
D07516441B2D9CEF00AE42E0 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = D07516401B2D9CEF00AE42E0 /* sqlite3.c */; };
D07516451B2D9CEF00AE42E0 /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = D07516411B2D9CEF00AE42E0 /* sqlite3.h */; };
D07516461B2D9CEF00AE42E0 /* sqlite3ext.h in Headers */ = {isa = PBXBuildFile; fileRef = D07516421B2D9CEF00AE42E0 /* sqlite3ext.h */; };
D075165C1B2EC5B000AE42E0 /* module.private.modulemap in Sources */ = {isa = PBXBuildFile; fileRef = D075165B1B2EC5B000AE42E0 /* module.private.modulemap */; };
D075165E1B2EC5B500AE42E0 /* module.modulemap in Sources */ = {isa = PBXBuildFile; fileRef = D075165D1B2EC5B500AE42E0 /* module.modulemap */; };
D075166A1B2EC7FE00AE42E0 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07516611B2EC7FE00AE42E0 /* Database.swift */; };
D075166B1B2EC7FE00AE42E0 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07516621B2EC7FE00AE42E0 /* Expression.swift */; };
D075166C1B2EC7FE00AE42E0 /* FTS.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07516631B2EC7FE00AE42E0 /* FTS.swift */; };
D075166E1B2EC7FE00AE42E0 /* Functions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07516651B2EC7FE00AE42E0 /* Functions.swift */; };
D075166F1B2EC7FE00AE42E0 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07516661B2EC7FE00AE42E0 /* Query.swift */; };
D07516701B2EC7FE00AE42E0 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07516671B2EC7FE00AE42E0 /* Schema.swift */; };
D07516711B2EC7FE00AE42E0 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07516681B2EC7FE00AE42E0 /* Statement.swift */; };
D07516721B2EC7FE00AE42E0 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07516691B2EC7FE00AE42E0 /* Value.swift */; };
D07516771B2EC90400AE42E0 /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = D07516741B2EC90400AE42E0 /* fts3_tokenizer.h */; };
D07516781B2EC90400AE42E0 /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = D07516751B2EC90400AE42E0 /* SQLite-Bridging.h */; };
D07516791B2EC90400AE42E0 /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = D07516761B2EC90400AE42E0 /* SQLite-Bridging.m */; };
D07FC7D31B4A3D6B0010B3F7 /* SwiftSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D07FC7D21B4A3D6B0010B3F7 /* SwiftSignalKit.framework */; };
D0E3A7501B28A7E300A402D9 /* Postbox.h in Headers */ = {isa = PBXBuildFile; fileRef = D0E3A74F1B28A7E300A402D9 /* Postbox.h */; settings = {ATTRIBUTES = (Public, ); }; };
D0E3A7561B28A7E300A402D9 /* Postbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0E3A74A1B28A7E300A402D9 /* Postbox.framework */; };
D0E3A75D1B28A7E300A402D9 /* PostboxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E3A75C1B28A7E300A402D9 /* PostboxTests.swift */; };
D0E3A7821B28ADD000A402D9 /* Postbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E3A7811B28ADD000A402D9 /* Postbox.swift */; };
D0E3A7841B28AE0900A402D9 /* Peer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E3A7831B28AE0900A402D9 /* Peer.swift */; };
D0E3A7881B28AE9C00A402D9 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E3A7871B28AE9C00A402D9 /* Coding.swift */; };
D0E3A79E1B28B50400A402D9 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E3A79D1B28B50400A402D9 /* Message.swift */; };
D0E3A7A21B28B7DC00A402D9 /* Media.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E3A7A11B28B7DC00A402D9 /* Media.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -23,12 +49,39 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
D003E4E51B38DBDB00C22CBC /* MessageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageView.swift; sourceTree = "<group>"; };
D044E15D1B2ACB9C001EE087 /* CodingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodingTests.swift; sourceTree = "<group>"; };
D044E1611B2AD667001EE087 /* MurMurHash32.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MurMurHash32.h; sourceTree = "<group>"; };
D044E1621B2AD677001EE087 /* MurMurHash32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MurMurHash32.m; sourceTree = "<group>"; };
D07516401B2D9CEF00AE42E0 /* sqlite3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sqlite3.c; sourceTree = "<group>"; };
D07516411B2D9CEF00AE42E0 /* sqlite3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqlite3.h; sourceTree = "<group>"; };
D07516421B2D9CEF00AE42E0 /* sqlite3ext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqlite3ext.h; sourceTree = "<group>"; };
D07516491B2D9E2500AE42E0 /* Postbox.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Postbox.xcconfig; path = Postbox/Config/Postbox.xcconfig; sourceTree = "<group>"; };
D075165B1B2EC5B000AE42E0 /* module.private.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.private.modulemap; sourceTree = "<group>"; };
D075165D1B2EC5B500AE42E0 /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
D07516611B2EC7FE00AE42E0 /* Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Database.swift; path = submodules/sqlite.swift/SQLite/Database.swift; sourceTree = SOURCE_ROOT; };
D07516621B2EC7FE00AE42E0 /* Expression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Expression.swift; path = submodules/sqlite.swift/SQLite/Expression.swift; sourceTree = SOURCE_ROOT; };
D07516631B2EC7FE00AE42E0 /* FTS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FTS.swift; path = submodules/sqlite.swift/SQLite/FTS.swift; sourceTree = SOURCE_ROOT; };
D07516651B2EC7FE00AE42E0 /* Functions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Functions.swift; path = submodules/sqlite.swift/SQLite/Functions.swift; sourceTree = SOURCE_ROOT; };
D07516661B2EC7FE00AE42E0 /* Query.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Query.swift; path = submodules/sqlite.swift/SQLite/Query.swift; sourceTree = SOURCE_ROOT; };
D07516671B2EC7FE00AE42E0 /* Schema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Schema.swift; path = submodules/sqlite.swift/SQLite/Schema.swift; sourceTree = SOURCE_ROOT; };
D07516681B2EC7FE00AE42E0 /* Statement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Statement.swift; path = submodules/sqlite.swift/SQLite/Statement.swift; sourceTree = SOURCE_ROOT; };
D07516691B2EC7FE00AE42E0 /* Value.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Value.swift; path = submodules/sqlite.swift/SQLite/Value.swift; sourceTree = SOURCE_ROOT; };
D07516741B2EC90400AE42E0 /* fts3_tokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fts3_tokenizer.h; sourceTree = "<group>"; };
D07516751B2EC90400AE42E0 /* SQLite-Bridging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SQLite-Bridging.h"; sourceTree = "<group>"; };
D07516761B2EC90400AE42E0 /* SQLite-Bridging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SQLite-Bridging.m"; sourceTree = "<group>"; };
D07FC7D21B4A3D6B0010B3F7 /* SwiftSignalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftSignalKit.framework; path = "../SSignalKit/build/Debug-iphoneos/SwiftSignalKit.framework"; sourceTree = "<group>"; };
D0E3A74A1B28A7E300A402D9 /* Postbox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Postbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D0E3A74E1B28A7E300A402D9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D0E3A74F1B28A7E300A402D9 /* Postbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Postbox.h; sourceTree = "<group>"; };
D0E3A7551B28A7E300A402D9 /* PostboxTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PostboxTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
D0E3A75B1B28A7E300A402D9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D0E3A75C1B28A7E300A402D9 /* PostboxTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostboxTests.swift; sourceTree = "<group>"; };
D0E3A7811B28ADD000A402D9 /* Postbox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Postbox.swift; sourceTree = "<group>"; };
D0E3A7831B28AE0900A402D9 /* Peer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Peer.swift; sourceTree = "<group>"; };
D0E3A7871B28AE9C00A402D9 /* Coding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Coding.swift; sourceTree = "<group>"; };
D0E3A79D1B28B50400A402D9 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = "<group>"; };
D0E3A7A11B28B7DC00A402D9 /* Media.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Media.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -43,6 +96,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D07FC7D31B4A3D6B0010B3F7 /* SwiftSignalKit.framework in Frameworks */,
D0E3A7561B28A7E300A402D9 /* Postbox.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -50,9 +104,56 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
D07515FC1B2C44A200AE42E0 /* thirdparty */ = {
isa = PBXGroup;
children = (
D07516731B2EC8C700AE42E0 /* sqlite.swift */,
);
name = thirdparty;
sourceTree = "<group>";
};
D075163D1B2D9CEF00AE42E0 /* PostboxPrivate */ = {
isa = PBXGroup;
children = (
D075165D1B2EC5B500AE42E0 /* module.modulemap */,
D075163F1B2D9CEF00AE42E0 /* sqlcipher */,
);
path = PostboxPrivate;
sourceTree = "<group>";
};
D075163F1B2D9CEF00AE42E0 /* sqlcipher */ = {
isa = PBXGroup;
children = (
D07516741B2EC90400AE42E0 /* fts3_tokenizer.h */,
D07516751B2EC90400AE42E0 /* SQLite-Bridging.h */,
D07516761B2EC90400AE42E0 /* SQLite-Bridging.m */,
D07516401B2D9CEF00AE42E0 /* sqlite3.c */,
D07516411B2D9CEF00AE42E0 /* sqlite3.h */,
D07516421B2D9CEF00AE42E0 /* sqlite3ext.h */,
);
path = sqlcipher;
sourceTree = "<group>";
};
D07516731B2EC8C700AE42E0 /* sqlite.swift */ = {
isa = PBXGroup;
children = (
D07516611B2EC7FE00AE42E0 /* Database.swift */,
D07516621B2EC7FE00AE42E0 /* Expression.swift */,
D07516631B2EC7FE00AE42E0 /* FTS.swift */,
D07516651B2EC7FE00AE42E0 /* Functions.swift */,
D07516661B2EC7FE00AE42E0 /* Query.swift */,
D07516671B2EC7FE00AE42E0 /* Schema.swift */,
D07516681B2EC7FE00AE42E0 /* Statement.swift */,
D07516691B2EC7FE00AE42E0 /* Value.swift */,
);
name = sqlite.swift;
sourceTree = "<group>";
};
D0E3A7401B28A7E300A402D9 = {
isa = PBXGroup;
children = (
D07FC7D21B4A3D6B0010B3F7 /* SwiftSignalKit.framework */,
D07516491B2D9E2500AE42E0 /* Postbox.xcconfig */,
D0E3A74C1B28A7E300A402D9 /* Postbox */,
D0E3A7591B28A7E300A402D9 /* PostboxTests */,
D0E3A74B1B28A7E300A402D9 /* Products */,
@ -71,7 +172,15 @@
D0E3A74C1B28A7E300A402D9 /* Postbox */ = {
isa = PBXGroup;
children = (
D0E3A74F1B28A7E300A402D9 /* Postbox.h */,
D075165B1B2EC5B000AE42E0 /* module.private.modulemap */,
D075163D1B2D9CEF00AE42E0 /* PostboxPrivate */,
D07515FC1B2C44A200AE42E0 /* thirdparty */,
D0E3A7871B28AE9C00A402D9 /* Coding.swift */,
D0E3A7831B28AE0900A402D9 /* Peer.swift */,
D0E3A79D1B28B50400A402D9 /* Message.swift */,
D0E3A7A11B28B7DC00A402D9 /* Media.swift */,
D003E4E51B38DBDB00C22CBC /* MessageView.swift */,
D0E3A7811B28ADD000A402D9 /* Postbox.swift */,
D0E3A74D1B28A7E300A402D9 /* Supporting Files */,
);
path = Postbox;
@ -80,6 +189,9 @@
D0E3A74D1B28A7E300A402D9 /* Supporting Files */ = {
isa = PBXGroup;
children = (
D044E1611B2AD667001EE087 /* MurMurHash32.h */,
D044E1621B2AD677001EE087 /* MurMurHash32.m */,
D0E3A74F1B28A7E300A402D9 /* Postbox.h */,
D0E3A74E1B28A7E300A402D9 /* Info.plist */,
);
name = "Supporting Files";
@ -90,6 +202,7 @@
children = (
D0E3A75C1B28A7E300A402D9 /* PostboxTests.swift */,
D0E3A75A1B28A7E300A402D9 /* Supporting Files */,
D044E15D1B2ACB9C001EE087 /* CodingTests.swift */,
);
path = PostboxTests;
sourceTree = "<group>";
@ -109,7 +222,12 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
D07516771B2EC90400AE42E0 /* fts3_tokenizer.h in Headers */,
D07516451B2D9CEF00AE42E0 /* sqlite3.h in Headers */,
D07516781B2EC90400AE42E0 /* SQLite-Bridging.h in Headers */,
D0E3A7501B28A7E300A402D9 /* Postbox.h in Headers */,
D07516461B2D9CEF00AE42E0 /* sqlite3ext.h in Headers */,
D044E1641B2AD718001EE087 /* MurMurHash32.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -158,6 +276,7 @@
D0E3A7411B28A7E300A402D9 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0630;
ORGANIZATIONNAME = Telegram;
TargetAttributes = {
@ -209,6 +328,25 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D07516701B2EC7FE00AE42E0 /* Schema.swift in Sources */,
D075165C1B2EC5B000AE42E0 /* module.private.modulemap in Sources */,
D0E3A7821B28ADD000A402D9 /* Postbox.swift in Sources */,
D0E3A79E1B28B50400A402D9 /* Message.swift in Sources */,
D075166E1B2EC7FE00AE42E0 /* Functions.swift in Sources */,
D044E1631B2AD677001EE087 /* MurMurHash32.m in Sources */,
D07516721B2EC7FE00AE42E0 /* Value.swift in Sources */,
D075166B1B2EC7FE00AE42E0 /* Expression.swift in Sources */,
D0E3A7A21B28B7DC00A402D9 /* Media.swift in Sources */,
D075166C1B2EC7FE00AE42E0 /* FTS.swift in Sources */,
D0E3A7881B28AE9C00A402D9 /* Coding.swift in Sources */,
D003E4E61B38DBDB00C22CBC /* MessageView.swift in Sources */,
D075165E1B2EC5B500AE42E0 /* module.modulemap in Sources */,
D07516791B2EC90400AE42E0 /* SQLite-Bridging.m in Sources */,
D07516711B2EC7FE00AE42E0 /* Statement.swift in Sources */,
D0E3A7841B28AE0900A402D9 /* Peer.swift in Sources */,
D075166A1B2EC7FE00AE42E0 /* Database.swift in Sources */,
D075166F1B2EC7FE00AE42E0 /* Query.swift in Sources */,
D07516441B2D9CEF00AE42E0 /* sqlite3.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -216,6 +354,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D044E15E1B2ACB9C001EE087 /* CodingTests.swift in Sources */,
D0E3A75D1B28A7E300A402D9 /* PostboxTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -233,6 +372,7 @@
/* Begin XCBuildConfiguration section */
D0E3A75E1B28A7E300A402D9 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D07516491B2D9E2500AE42E0 /* Postbox.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
@ -281,6 +421,7 @@
};
D0E3A75F1B28A7E300A402D9 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D07516491B2D9E2500AE42E0 /* Postbox.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
@ -322,29 +463,55 @@
};
D0E3A7611B28A7E300A402D9 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D07516491B2D9E2500AE42E0 /* Postbox.xcconfig */;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"/Users/peter/Documents/PostBoxTest/submodules/SSignalKit/build/Debug-iphoneos",
);
INFOPLIST_FILE = Postbox/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = (
"-DSQLITE_TEMP_STORE=2",
"-DSQLITE_HAS_CODEC=1",
"-DSQLCIPHER_CRYPTO_CC=1",
"-DSQLITE_ENABLE_FTS3",
);
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
D0E3A7621B28A7E300A402D9 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"/Users/peter/Documents/PostBoxTest/submodules/SSignalKit/build/Debug-iphoneos",
);
INFOPLIST_FILE = Postbox/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = (
"-DSQLITE_TEMP_STORE=2",
"-DSQLITE_HAS_CODEC=1",
"-DSQLCIPHER_CRYPTO_CC=1",
"-DSQLITE_ENABLE_FTS3",
);
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
@ -352,10 +519,12 @@
};
D0E3A7641B28A7E300A402D9 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D07516491B2D9E2500AE42E0 /* Postbox.xcconfig */;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
"/Users/peter/Documents/PostBoxTest/submodules/SSignalKit/build/Debug-iphoneos",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@ -373,6 +542,7 @@
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
"/Users/peter/Documents/PostBoxTest/submodules/SSignalKit/build/Debug-iphoneos",
);
INFOPLIST_FILE = PostboxTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
@ -399,6 +569,7 @@
D0E3A7621B28A7E300A402D9 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D0E3A7631B28A7E300A402D9 /* Build configuration list for PBXNativeTarget "PostboxTests" */ = {
isa = XCConfigurationList;
@ -407,6 +578,7 @@
D0E3A7651B28A7E300A402D9 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};

View File

@ -0,0 +1,2 @@
SWIFT_INCLUDE_PATHS = $(SRCROOT)/Postbox
MODULEMAP_PRIVATE_FILE = $(SRCROOT)/Postbox/module.private.modulemap

365
Postbox/MessageView.swift Normal file
View File

@ -0,0 +1,365 @@
import Foundation
public final class MutableMessageView: Printable {
public struct RemoveContext {
var invalidEarlier: Set<MessageId.Namespace>
var invalidLater: Set<MessageId.Namespace>
var removedMessages: Bool
init() {
self.invalidEarlier = []
self.invalidLater = []
self.removedMessages = false
}
}
let namespaces: [MessageId.Namespace]
let count: Int
var earlier: [MessageId.Namespace : Message] = [:]
var later: [MessageId.Namespace : Message] = [:]
var messages: [Message]
public init(namespaces: [MessageId.Namespace], count: Int, earlier: [MessageId.Namespace : Message], messages: [Message], later: [MessageId.Namespace : Message]) {
self.namespaces = namespaces
self.count = count
self.earlier = earlier
self.later = later
self.messages = messages
}
public func add(message: Message) {
if self.messages.count == 0 {
self.messages.append(message)
} else {
var first = MessageIndex(self.messages[self.messages.count - 1])
var last = MessageIndex(self.messages[0])
var next: MessageIndex?
for namespace in self.namespaces {
if let message = later[namespace] {
let messageIndex = MessageIndex(message)
if next == nil || messageIndex < next! {
next = messageIndex
}
}
}
let index = MessageIndex(message)
if index < last {
let earlierMessage = self.earlier[message.id.namespace]
if earlierMessage == nil || earlierMessage!.id.id < message.id.id {
if self.messages.count < self.count {
self.messages.insert(message, atIndex: 0)
} else {
self.earlier[message.id.namespace] = message
}
}
} else if index > first {
if next != nil && index > next! {
let laterMessage = self.later[message.id.namespace]
if laterMessage == nil || laterMessage!.id.id > message.id.id {
if self.messages.count < self.count {
self.messages.append(message)
} else {
self.later[message.id.namespace] = message
}
}
} else {
self.messages.append(message)
if self.messages.count > self.count {
let earliest = self.messages[0]
self.earlier[earliest.id.namespace] = earliest
self.messages.removeAtIndex(0)
}
}
} else if index != last && index != first {
var i = self.messages.count
while i >= 1 {
if MessageIndex(self.messages[i - 1]) < index {
break
}
i--
}
self.messages.insert(message, atIndex: i)
if self.messages.count > self.count {
let earliest = self.messages[0]
self.earlier[earliest.id.namespace] = earliest
self.messages.removeAtIndex(0)
}
}
}
}
public func remove(ids: Set<MessageId>, context: RemoveContext? = nil) -> RemoveContext {
var updatedContext = RemoveContext()
if let context = context {
updatedContext = context
}
for (_, message) in self.earlier {
if ids.contains(message.id) {
updatedContext.invalidEarlier.insert(message.id.namespace)
}
}
for (_, message) in self.later {
if ids.contains(message.id) {
updatedContext.invalidLater.insert(message.id.namespace)
}
}
if self.messages.count != 0 {
var i = self.messages.count - 1
while i >= 0 {
if ids.contains(self.messages[i].id) {
self.messages.removeAtIndex(i)
updatedContext.removedMessages = true
}
i--
}
}
return updatedContext
}
public func complete(context: RemoveContext, fetchEarlier: (MessageId.Namespace, MessageId.Id?, Int) -> [Message], fetchLater: (MessageId.Namespace, MessageId.Id?, Int) -> [Message]) {
if context.removedMessages {
var addedMessages: [Message] = []
var latestAnchor: MessageIndex?
if let lastMessage = self.messages.last {
latestAnchor = MessageIndex(lastMessage)
}
if latestAnchor == nil {
var laterMessages: [Message] = []
for (_, message) in self.later {
let messageIndex = MessageIndex(message)
if latestAnchor == nil || latestAnchor! > messageIndex {
latestAnchor = messageIndex
}
}
}
for namespace in self.namespaces {
if let later = self.later[namespace] {
addedMessages += fetchLater(namespace, later.id.id - 1, self.count)
}
if let earlier = self.earlier[namespace] {
addedMessages += fetchEarlier(namespace, earlier.id.id + 1, self.count)
}
}
addedMessages += self.messages
addedMessages.sort({ MessageIndex($0) < MessageIndex($1) })
var i = addedMessages.count - 1
while i >= 1 {
if addedMessages[i].id == addedMessages[i - 1].id {
addedMessages.removeAtIndex(i)
}
i--
}
self.messages = []
var anchorIndex = addedMessages.count - 1
if let latestAnchor = latestAnchor {
var i = addedMessages.count - 1
while i >= 0 {
if MessageIndex(addedMessages[i]) <= latestAnchor {
anchorIndex = i
break
}
i--
}
}
self.later.removeAll(keepCapacity: true)
if anchorIndex + 1 < addedMessages.count {
for namespace in self.namespaces {
var i = anchorIndex + 1
while i < addedMessages.count {
if addedMessages[i].id.namespace == namespace {
self.later[namespace] = addedMessages[i]
break
}
i++
}
}
}
i = anchorIndex
while i >= 0 && i > anchorIndex - self.count {
self.messages.insert(addedMessages[i], atIndex: 0)
i--
}
self.earlier.removeAll(keepCapacity: true)
if anchorIndex - self.count >= 0 {
for namespace in self.namespaces {
i = anchorIndex - self.count
while i >= 0 {
if addedMessages[i].id.namespace == namespace {
self.earlier[namespace] = addedMessages[i]
break
}
i--
}
}
}
}
else {
for namespace in context.invalidEarlier {
var earlyId: MessageId.Id?
var i = 0
while i < self.messages.count {
if self.messages[i].id.namespace == namespace {
earlyId = self.messages[i].id.id
break
}
i++
}
let earlierMessages = fetchEarlier(namespace, earlyId, 1)
if earlierMessages.count == 0 {
self.earlier.removeValueForKey(namespace)
} else {
self.earlier[namespace] = earlierMessages[0]
}
}
for namespace in context.invalidLater {
var lateId: MessageId.Id?
var i = self.messages.count - 1
while i >= 0 {
if self.messages[i].id.namespace == namespace {
lateId = self.messages[i].id.id
break
}
i--
}
let laterMessages = fetchLater(namespace, lateId, 1)
if laterMessages.count == 0 {
self.later.removeValueForKey(namespace)
} else {
self.later[namespace] = laterMessages[0]
}
}
}
}
public var description: String {
var string = ""
string += "...("
var first = true
for namespace in self.namespaces {
if let value = self.earlier[namespace] {
if first {
first = false
} else {
string += ", "
}
string += "\(namespace): \(value.id.id)\(value.timestamp)"
}
}
string += ") —— "
string += "["
first = true
for message in self.messages {
if first {
first = false
} else {
string += ", "
}
string += "\(message.id.namespace): \(message.id.id)\(message.timestamp)"
}
string += "]"
string += " —— ("
first = true
for namespace in self.namespaces {
if let value = self.later[namespace] {
if first {
first = false
} else {
string += ", "
}
string += "\(namespace): \(value.id.id)\(value.timestamp)"
}
}
string += ")..."
return string
}
}
public final class MessageView: Printable {
public let hasEarlier: Bool
private let earlierIds: [MessageIndex]
public let hasLater: Bool
private let laterIds: [MessageIndex]
public let messages: [Message]
init(_ mutableView: MutableMessageView) {
self.hasEarlier = mutableView.earlier.count != 0
self.hasLater = mutableView.later.count != 0
self.messages = mutableView.messages
var earlierIds: [MessageIndex] = []
for (_, message) in mutableView.earlier {
earlierIds.append(MessageIndex(message))
}
self.earlierIds = earlierIds
var laterIds: [MessageIndex] = []
for (_, message) in mutableView.later {
laterIds.append(MessageIndex(message))
}
self.laterIds = laterIds
}
public var description: String {
var string = ""
if self.hasEarlier {
string += "more("
var first = true
for id in self.earlierIds {
if first {
first = false
} else {
string += ", "
}
string += "\(id.id.namespace): \(id.id.id)\(id.timestamp)"
}
string += ") "
}
string += "["
var first = true
for message in self.messages {
if first {
first = false
} else {
string += ", "
}
string += "\(message.id.namespace): \(message.id.id)\(message.timestamp)"
}
string += "]"
if self.hasLater {
string += " more("
var first = true
for id in self.laterIds {
if first {
first = false
} else {
string += ", "
}
string += "\(id.id.namespace): \(id.id.id)\(id.timestamp)"
}
string += ")"
}
return string
}
}

9
Postbox/MurMurHash32.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef Postbox_MurMurHash32_h
#define Postbox_MurMurHash32_h
#import <stdint.h>
int32_t murMurHash32(void *bytes, int length);
int32_t murMurHashString32(const char *s);
#endif

98
Postbox/MurMurHash32.m Normal file
View File

@ -0,0 +1,98 @@
#import "MurMurHash32.h"
#include <stdlib.h>
#include <string.h>
#define FORCE_INLINE __attribute__((always_inline))
static inline uint32_t rotl32 ( uint32_t x, int8_t r )
{
return (x << r) | (x >> (32 - r));
}
#define ROTL32(x,y) rotl32(x,y)
static FORCE_INLINE uint32_t getblock ( const uint32_t * p, int i )
{
return p[i];
}
static FORCE_INLINE uint32_t fmix ( uint32_t h )
{
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
static void murMurHash32Impl(const void *key, int len, uint32_t seed, void *out)
{
const uint8_t * data = (const uint8_t*)key;
const int nblocks = len / 4;
uint32_t h1 = seed;
const uint32_t c1 = 0xcc9e2d51;
const uint32_t c2 = 0x1b873593;
//----------
// body
const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
for(int i = -nblocks; i; i++)
{
uint32_t k1 = getblock(blocks,i);
k1 *= c1;
k1 = ROTL32(k1,15);
k1 *= c2;
h1 ^= k1;
h1 = ROTL32(h1,13);
h1 = h1*5+0xe6546b64;
}
//----------
// tail
const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
uint32_t k1 = 0;
switch(len & 3)
{
case 3: k1 ^= tail[2] << 16;
case 2: k1 ^= tail[1] << 8;
case 1: k1 ^= tail[0];
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
};
//----------
// finalization
h1 ^= len;
h1 = fmix(h1);
*(uint32_t*)out = h1;
}
int32_t murMurHash32(void *bytes, int length)
{
int32_t result = 0;
murMurHash32Impl(bytes, length, -137723950, &result);
return result;
}
int32_t murMurHashString32(const char *s)
{
int32_t result = 0;
murMurHash32Impl(s, (int)strlen(s), -137723950, &result);
return result;
}

View File

@ -16,4 +16,4 @@ FOUNDATION_EXPORT const unsigned char PostboxVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <Postbox/PublicHeader.h>
#import <Postbox/MurMurHash32.h>

View File

@ -0,0 +1,7 @@
module sqlcipher {
header "sqlcipher/sqlite3.h"
header "sqlcipher/sqlite3ext.h"
header "sqlcipher/SQLite-Bridging.h"
header "sqlcipher/fts3_tokenizer.h"
export *
}

View File

@ -0,0 +1,56 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright (c) 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
@import Foundation;
typedef struct SQLiteHandle SQLiteHandle;
typedef struct SQLiteContext SQLiteContext;
typedef struct SQLiteValue SQLiteValue;
NS_ASSUME_NONNULL_BEGIN
typedef int (^_SQLiteBusyHandlerCallback)(int times);
int _SQLiteBusyHandler(SQLiteHandle * handle, _SQLiteBusyHandlerCallback __nullable callback);
typedef void (^_SQLiteTraceCallback)(const char * SQL);
void _SQLiteTrace(SQLiteHandle * handle, _SQLiteTraceCallback __nullable callback);
typedef void (^_SQLiteUpdateHookCallback)(int operation, const char * db, const char * table, long long rowid);
void _SQLiteUpdateHook(SQLiteHandle * handle, _SQLiteUpdateHookCallback __nullable callback);
typedef int (^_SQLiteCommitHookCallback)();
void _SQLiteCommitHook(SQLiteHandle * handle, _SQLiteCommitHookCallback __nullable callback);
typedef void (^_SQLiteRollbackHookCallback)();
void _SQLiteRollbackHook(SQLiteHandle * handle, _SQLiteRollbackHookCallback __nullable callback);
typedef void (^_SQLiteCreateFunctionCallback)(SQLiteContext * context, int argc, SQLiteValue * __nonnull * __nonnull argv);
int _SQLiteCreateFunction(SQLiteHandle * handle, const char * name, int argc, int deterministic, _SQLiteCreateFunctionCallback __nullable callback);
typedef int (^_SQLiteCreateCollationCallback)(const char * lhs, const char * rhs);
int _SQLiteCreateCollation(SQLiteHandle * handle, const char * name, _SQLiteCreateCollationCallback __nullable callback);
typedef NSString * __nullable (^_SQLiteTokenizerNextCallback)(const char * input, int * inputOffset, int * inputLength);
int _SQLiteRegisterTokenizer(SQLiteHandle * db, const char * module, const char * tokenizer, __nullable _SQLiteTokenizerNextCallback callback);
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,217 @@
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright (c) 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "SQLite-Bridging.h"
#import "fts3_tokenizer.h"
static int __SQLiteBusyHandler(void * context, int tries) {
return ((__bridge _SQLiteBusyHandlerCallback)context)(tries);
}
int _SQLiteBusyHandler(SQLiteHandle * handle, _SQLiteBusyHandlerCallback callback) {
if (callback) {
return sqlite3_busy_handler((sqlite3 *)handle, __SQLiteBusyHandler, (__bridge void *)callback);
} else {
return sqlite3_busy_handler((sqlite3 *)handle, 0, 0);
}
}
static void __SQLiteTrace(void * context, const char * SQL) {
((__bridge _SQLiteTraceCallback)context)(SQL);
}
void _SQLiteTrace(SQLiteHandle * handle, _SQLiteTraceCallback callback) {
if (callback) {
sqlite3_trace((sqlite3 *)handle, __SQLiteTrace, (__bridge void *)callback);
} else {
sqlite3_trace((sqlite3 *)handle, 0, 0);
}
}
static void __SQLiteUpdateHook(void * context, int operation, const char * db, const char * table, long long rowid) {
((__bridge _SQLiteUpdateHookCallback)context)(operation, db, table, rowid);
}
void _SQLiteUpdateHook(SQLiteHandle * handle, _SQLiteUpdateHookCallback callback) {
sqlite3_update_hook((sqlite3 *)handle, __SQLiteUpdateHook, (__bridge void *)callback);
}
static int __SQLiteCommitHook(void * context) {
return ((__bridge _SQLiteCommitHookCallback)context)();
}
void _SQLiteCommitHook(SQLiteHandle * handle, _SQLiteCommitHookCallback callback) {
sqlite3_commit_hook((sqlite3 *)handle, __SQLiteCommitHook, (__bridge void *)callback);
}
static void __SQLiteRollbackHook(void * context) {
((__bridge _SQLiteRollbackHookCallback)context)();
}
void _SQLiteRollbackHook(SQLiteHandle * handle, _SQLiteRollbackHookCallback callback) {
sqlite3_rollback_hook((sqlite3 *)handle, __SQLiteRollbackHook, (__bridge void *)callback);
}
static void __SQLiteCreateFunction(sqlite3_context * context, int argc, sqlite3_value ** argv) {
((__bridge _SQLiteCreateFunctionCallback)sqlite3_user_data(context))((SQLiteContext *)context, argc, (SQLiteValue **)argv);
}
int _SQLiteCreateFunction(SQLiteHandle * handle, const char * name, int argc, int deterministic, _SQLiteCreateFunctionCallback callback) {
if (callback) {
int flags = SQLITE_UTF8;
if (deterministic) {
#ifdef SQLITE_DETERMINISTIC
flags |= SQLITE_DETERMINISTIC;
#endif
}
return sqlite3_create_function_v2((sqlite3 *)handle, name, -1, flags, (__bridge void *)callback, &__SQLiteCreateFunction, 0, 0, 0);
} else {
return sqlite3_create_function_v2((sqlite3 *)handle, name, 0, 0, 0, 0, 0, 0, 0);
}
}
static int __SQLiteCreateCollation(void * context, int len_lhs, const void * lhs, int len_rhs, const void * rhs) {
return ((__bridge _SQLiteCreateCollationCallback)context)(lhs, rhs);
}
int _SQLiteCreateCollation(SQLiteHandle * handle, const char * name, _SQLiteCreateCollationCallback callback) {
if (callback) {
return sqlite3_create_collation_v2((sqlite3 *)handle, name, SQLITE_UTF8, (__bridge void *)callback, &__SQLiteCreateCollation, 0);
} else {
return sqlite3_create_collation_v2((sqlite3 *)handle, name, 0, 0, 0, 0);
}
}
#pragma mark - FTS
typedef struct __SQLiteTokenizer {
sqlite3_tokenizer base;
__unsafe_unretained _SQLiteTokenizerNextCallback callback;
} __SQLiteTokenizer;
typedef struct __SQLiteTokenizerCursor {
void * base;
const char * input;
int inputOffset;
int inputLength;
int idx;
} __SQLiteTokenizerCursor;
static NSMutableDictionary * __SQLiteTokenizerMap;
static int __SQLiteTokenizerCreate(int argc, const char * const * argv, sqlite3_tokenizer ** ppTokenizer) {
__SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)sqlite3_malloc(sizeof(__SQLiteTokenizer));
if (!tokenizer) {
return SQLITE_NOMEM;
}
memset(tokenizer, 0, sizeof(* tokenizer)); // FIXME: needed?
NSString * key = [NSString stringWithUTF8String:argv[0]];
tokenizer->callback = [__SQLiteTokenizerMap objectForKey:key];
if (!tokenizer->callback) {
return SQLITE_ERROR;
}
*ppTokenizer = &tokenizer->base;
return SQLITE_OK;
}
static int __SQLiteTokenizerDestroy(sqlite3_tokenizer * pTokenizer) {
sqlite3_free(pTokenizer);
return SQLITE_OK;
}
static int __SQLiteTokenizerOpen(sqlite3_tokenizer * pTokenizer, const char * pInput, int nBytes, sqlite3_tokenizer_cursor ** ppCursor) {
__SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)sqlite3_malloc(sizeof(__SQLiteTokenizerCursor));
if (!cursor) {
return SQLITE_NOMEM;
}
cursor->input = pInput;
cursor->inputOffset = 0;
cursor->inputLength = 0;
cursor->idx = 0;
*ppCursor = (sqlite3_tokenizer_cursor *)cursor;
return SQLITE_OK;
}
static int __SQLiteTokenizerClose(sqlite3_tokenizer_cursor * pCursor) {
sqlite3_free(pCursor);
return SQLITE_OK;
}
static int __SQLiteTokenizerNext(sqlite3_tokenizer_cursor * pCursor, const char ** ppToken, int * pnBytes, int * piStartOffset, int * piEndOffset, int * piPosition) {
__SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)pCursor;
__SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)cursor->base;
cursor->inputOffset += cursor->inputLength;
const char * input = cursor->input + cursor->inputOffset;
const char * token = [tokenizer->callback(input, &cursor->inputOffset, &cursor->inputLength) cStringUsingEncoding:NSUTF8StringEncoding];
if (!token) {
return SQLITE_DONE;
}
*ppToken = token;
*pnBytes = (int)strlen(token);
*piStartOffset = cursor->inputOffset;
*piEndOffset = cursor->inputOffset + cursor->inputLength;
*piPosition = cursor->idx++;
return SQLITE_OK;
}
static const sqlite3_tokenizer_module __SQLiteTokenizerModule = {
0,
__SQLiteTokenizerCreate,
__SQLiteTokenizerDestroy,
__SQLiteTokenizerOpen,
__SQLiteTokenizerClose,
__SQLiteTokenizerNext
};
int _SQLiteRegisterTokenizer(SQLiteHandle * db, const char * moduleName, const char * submoduleName, _SQLiteTokenizerNextCallback callback) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
__SQLiteTokenizerMap = [NSMutableDictionary new];
});
sqlite3_stmt * stmt;
int status = sqlite3_prepare_v2((sqlite3 *)db, "SELECT fts3_tokenizer(?, ?)", -1, &stmt, 0);
if (status != SQLITE_OK ){
return status;
}
const sqlite3_tokenizer_module * pModule = &__SQLiteTokenizerModule;
sqlite3_bind_text(stmt, 1, moduleName, -1, SQLITE_STATIC);
sqlite3_bind_blob(stmt, 2, &pModule, sizeof(pModule), SQLITE_STATIC);
sqlite3_step(stmt);
status = sqlite3_finalize(stmt);
if (status != SQLITE_OK ){
return status;
}
[__SQLiteTokenizerMap setObject:[callback copy] forKey:[NSString stringWithUTF8String:submoduleName]];
return SQLITE_OK;
}

View File

@ -0,0 +1,161 @@
/*
** 2006 July 10
**
** The author disclaims copyright to this source code.
**
*************************************************************************
** Defines the interface to tokenizers used by fulltext-search. There
** are three basic components:
**
** sqlite3_tokenizer_module is a singleton defining the tokenizer
** interface functions. This is essentially the class structure for
** tokenizers.
**
** sqlite3_tokenizer is used to define a particular tokenizer, perhaps
** including customization information defined at creation time.
**
** sqlite3_tokenizer_cursor is generated by a tokenizer to generate
** tokens from a particular input.
*/
#ifndef _FTS3_TOKENIZER_H_
#define _FTS3_TOKENIZER_H_
/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time.
** If tokenizers are to be allowed to call sqlite3_*() functions, then
** we will need a way to register the API consistently.
*/
#include "sqlite3.h"
/*
** Structures used by the tokenizer interface. When a new tokenizer
** implementation is registered, the caller provides a pointer to
** an sqlite3_tokenizer_module containing pointers to the callback
** functions that make up an implementation.
**
** When an fts3 table is created, it passes any arguments passed to
** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the
** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer
** implementation. The xCreate() function in turn returns an
** sqlite3_tokenizer structure representing the specific tokenizer to
** be used for the fts3 table (customized by the tokenizer clause arguments).
**
** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen()
** method is called. It returns an sqlite3_tokenizer_cursor object
** that may be used to tokenize a specific input buffer based on
** the tokenization rules supplied by a specific sqlite3_tokenizer
** object.
*/
typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module;
typedef struct sqlite3_tokenizer sqlite3_tokenizer;
typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor;
struct sqlite3_tokenizer_module {
/*
** Structure version. Should always be set to 0 or 1.
*/
int iVersion;
/*
** Create a new tokenizer. The values in the argv[] array are the
** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL
** TABLE statement that created the fts3 table. For example, if
** the following SQL is executed:
**
** CREATE .. USING fts3( ... , tokenizer <tokenizer-name> arg1 arg2)
**
** then argc is set to 2, and the argv[] array contains pointers
** to the strings "arg1" and "arg2".
**
** This method should return either SQLITE_OK (0), or an SQLite error
** code. If SQLITE_OK is returned, then *ppTokenizer should be set
** to point at the newly created tokenizer structure. The generic
** sqlite3_tokenizer.pModule variable should not be initialized by
** this callback. The caller will do so.
*/
int (*xCreate)(
int argc, /* Size of argv array */
const char *const*argv, /* Tokenizer argument strings */
sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */
);
/*
** Destroy an existing tokenizer. The fts3 module calls this method
** exactly once for each successful call to xCreate().
*/
int (*xDestroy)(sqlite3_tokenizer *pTokenizer);
/*
** Create a tokenizer cursor to tokenize an input buffer. The caller
** is responsible for ensuring that the input buffer remains valid
** until the cursor is closed (using the xClose() method).
*/
int (*xOpen)(
sqlite3_tokenizer *pTokenizer, /* Tokenizer object */
const char *pInput, int nBytes, /* Input buffer */
sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */
);
/*
** Destroy an existing tokenizer cursor. The fts3 module calls this
** method exactly once for each successful call to xOpen().
*/
int (*xClose)(sqlite3_tokenizer_cursor *pCursor);
/*
** Retrieve the next token from the tokenizer cursor pCursor. This
** method should either return SQLITE_OK and set the values of the
** "OUT" variables identified below, or SQLITE_DONE to indicate that
** the end of the buffer has been reached, or an SQLite error code.
**
** *ppToken should be set to point at a buffer containing the
** normalized version of the token (i.e. after any case-folding and/or
** stemming has been performed). *pnBytes should be set to the length
** of this buffer in bytes. The input text that generated the token is
** identified by the byte offsets returned in *piStartOffset and
** *piEndOffset. *piStartOffset should be set to the index of the first
** byte of the token in the input buffer. *piEndOffset should be set
** to the index of the first byte just past the end of the token in
** the input buffer.
**
** The buffer *ppToken is set to point at is managed by the tokenizer
** implementation. It is only required to be valid until the next call
** to xNext() or xClose().
*/
/* TODO(shess) current implementation requires pInput to be
** nul-terminated. This should either be fixed, or pInput/nBytes
** should be converted to zInput.
*/
int (*xNext)(
sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */
const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */
int *piStartOffset, /* OUT: Byte offset of token in input buffer */
int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */
int *piPosition /* OUT: Number of tokens returned before this one */
);
/***********************************************************************
** Methods below this point are only available if iVersion>=1.
*/
/*
** Configure the language id of a tokenizer cursor.
*/
int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid);
};
struct sqlite3_tokenizer {
const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */
/* Tokenizer implementations will typically add additional fields */
};
struct sqlite3_tokenizer_cursor {
sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */
/* Tokenizer implementations will typically add additional fields */
};
int fts3_global_term_cnt(int iTerm, int iCol);
int fts3_term_cnt(int iTerm, int iCol);
#endif /* _FTS3_TOKENIZER_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,487 @@
/*
** 2006 June 7
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the SQLite interface for use by
** shared libraries that want to be imported as extensions into
** an SQLite instance. Shared libraries that intend to be loaded
** as extensions by SQLite should #include this file instead of
** sqlite3.h.
*/
#ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_
#include "sqlite3.h"
typedef struct sqlite3_api_routines sqlite3_api_routines;
/*
** The following structure holds pointers to all of the SQLite API
** routines.
**
** WARNING: In order to maintain backwards compatibility, add new
** interfaces to the end of this structure only. If you insert new
** interfaces in the middle of this structure, then older different
** versions of SQLite will not be able to load each others' shared
** libraries!
*/
struct sqlite3_api_routines {
void * (*aggregate_context)(sqlite3_context*,int nBytes);
int (*aggregate_count)(sqlite3_context*);
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
int (*bind_double)(sqlite3_stmt*,int,double);
int (*bind_int)(sqlite3_stmt*,int,int);
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
int (*bind_null)(sqlite3_stmt*,int);
int (*bind_parameter_count)(sqlite3_stmt*);
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
int (*busy_timeout)(sqlite3*,int ms);
int (*changes)(sqlite3*);
int (*close)(sqlite3*);
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const char*));
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const void*));
const void * (*column_blob)(sqlite3_stmt*,int iCol);
int (*column_bytes)(sqlite3_stmt*,int iCol);
int (*column_bytes16)(sqlite3_stmt*,int iCol);
int (*column_count)(sqlite3_stmt*pStmt);
const char * (*column_database_name)(sqlite3_stmt*,int);
const void * (*column_database_name16)(sqlite3_stmt*,int);
const char * (*column_decltype)(sqlite3_stmt*,int i);
const void * (*column_decltype16)(sqlite3_stmt*,int);
double (*column_double)(sqlite3_stmt*,int iCol);
int (*column_int)(sqlite3_stmt*,int iCol);
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
const char * (*column_name)(sqlite3_stmt*,int);
const void * (*column_name16)(sqlite3_stmt*,int);
const char * (*column_origin_name)(sqlite3_stmt*,int);
const void * (*column_origin_name16)(sqlite3_stmt*,int);
const char * (*column_table_name)(sqlite3_stmt*,int);
const void * (*column_table_name16)(sqlite3_stmt*,int);
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
const void * (*column_text16)(sqlite3_stmt*,int iCol);
int (*column_type)(sqlite3_stmt*,int iCol);
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
int (*complete)(const char*sql);
int (*complete16)(const void*sql);
int (*create_collation)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_collation16)(sqlite3*,const void*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_function)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_function16)(sqlite3*,const void*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
int (*data_count)(sqlite3_stmt*pStmt);
sqlite3 * (*db_handle)(sqlite3_stmt*);
int (*declare_vtab)(sqlite3*,const char*);
int (*enable_shared_cache)(int);
int (*errcode)(sqlite3*db);
const char * (*errmsg)(sqlite3*);
const void * (*errmsg16)(sqlite3*);
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
int (*expired)(sqlite3_stmt*);
int (*finalize)(sqlite3_stmt*pStmt);
void (*free)(void*);
void (*free_table)(char**result);
int (*get_autocommit)(sqlite3*);
void * (*get_auxdata)(sqlite3_context*,int);
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
int (*global_recover)(void);
void (*interruptx)(sqlite3*);
sqlite_int64 (*last_insert_rowid)(sqlite3*);
const char * (*libversion)(void);
int (*libversion_number)(void);
void *(*malloc)(int);
char * (*mprintf)(const char*,...);
int (*open)(const char*,sqlite3**);
int (*open16)(const void*,sqlite3**);
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
void *(*realloc)(void*,int);
int (*reset)(sqlite3_stmt*pStmt);
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_double)(sqlite3_context*,double);
void (*result_error)(sqlite3_context*,const char*,int);
void (*result_error16)(sqlite3_context*,const void*,int);
void (*result_int)(sqlite3_context*,int);
void (*result_int64)(sqlite3_context*,sqlite_int64);
void (*result_null)(sqlite3_context*);
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_value)(sqlite3_context*,sqlite3_value*);
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
char * (*snprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
void (*thread_cleanup)(void);
int (*total_changes)(sqlite3*);
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
sqlite_int64),void*);
void * (*user_data)(sqlite3_context*);
const void * (*value_blob)(sqlite3_value*);
int (*value_bytes)(sqlite3_value*);
int (*value_bytes16)(sqlite3_value*);
double (*value_double)(sqlite3_value*);
int (*value_int)(sqlite3_value*);
sqlite_int64 (*value_int64)(sqlite3_value*);
int (*value_numeric_type)(sqlite3_value*);
const unsigned char * (*value_text)(sqlite3_value*);
const void * (*value_text16)(sqlite3_value*);
const void * (*value_text16be)(sqlite3_value*);
const void * (*value_text16le)(sqlite3_value*);
int (*value_type)(sqlite3_value*);
char *(*vmprintf)(const char*,va_list);
/* Added ??? */
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
/* Added by 3.3.13 */
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
int (*clear_bindings)(sqlite3_stmt*);
/* Added by 3.4.1 */
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
void (*xDestroy)(void *));
/* Added by 3.5.0 */
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
int (*blob_bytes)(sqlite3_blob*);
int (*blob_close)(sqlite3_blob*);
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
int,sqlite3_blob**);
int (*blob_read)(sqlite3_blob*,void*,int,int);
int (*blob_write)(sqlite3_blob*,const void*,int,int);
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*),
void(*)(void*));
int (*file_control)(sqlite3*,const char*,int,void*);
sqlite3_int64 (*memory_highwater)(int);
sqlite3_int64 (*memory_used)(void);
sqlite3_mutex *(*mutex_alloc)(int);
void (*mutex_enter)(sqlite3_mutex*);
void (*mutex_free)(sqlite3_mutex*);
void (*mutex_leave)(sqlite3_mutex*);
int (*mutex_try)(sqlite3_mutex*);
int (*open_v2)(const char*,sqlite3**,int,const char*);
int (*release_memory)(int);
void (*result_error_nomem)(sqlite3_context*);
void (*result_error_toobig)(sqlite3_context*);
int (*sleep)(int);
void (*soft_heap_limit)(int);
sqlite3_vfs *(*vfs_find)(const char*);
int (*vfs_register)(sqlite3_vfs*,int);
int (*vfs_unregister)(sqlite3_vfs*);
int (*xthreadsafe)(void);
void (*result_zeroblob)(sqlite3_context*,int);
void (*result_error_code)(sqlite3_context*,int);
int (*test_control)(int, ...);
void (*randomness)(int,void*);
sqlite3 *(*context_db_handle)(sqlite3_context*);
int (*extended_result_codes)(sqlite3*,int);
int (*limit)(sqlite3*,int,int);
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
const char *(*sql)(sqlite3_stmt*);
int (*status)(int,int*,int*,int);
int (*backup_finish)(sqlite3_backup*);
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
int (*backup_pagecount)(sqlite3_backup*);
int (*backup_remaining)(sqlite3_backup*);
int (*backup_step)(sqlite3_backup*,int);
const char *(*compileoption_get)(int);
int (*compileoption_used)(const char*);
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
void(*xDestroy)(void*));
int (*db_config)(sqlite3*,int,...);
sqlite3_mutex *(*db_mutex)(sqlite3*);
int (*db_status)(sqlite3*,int,int*,int*,int);
int (*extended_errcode)(sqlite3*);
void (*log)(int,const char*,...);
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
const char *(*sourceid)(void);
int (*stmt_status)(sqlite3_stmt*,int,int);
int (*strnicmp)(const char*,const char*,int);
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
int (*wal_autocheckpoint)(sqlite3*,int);
int (*wal_checkpoint)(sqlite3*,const char*);
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
int (*vtab_config)(sqlite3*,int op,...);
int (*vtab_on_conflict)(sqlite3*);
/* Version 3.7.16 and later */
int (*close_v2)(sqlite3*);
const char *(*db_filename)(sqlite3*,const char*);
int (*db_readonly)(sqlite3*,const char*);
int (*db_release_memory)(sqlite3*);
const char *(*errstr)(int);
int (*stmt_busy)(sqlite3_stmt*);
int (*stmt_readonly)(sqlite3_stmt*);
int (*stricmp)(const char*,const char*);
int (*uri_boolean)(const char*,const char*,int);
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
const char *(*uri_parameter)(const char*,const char*);
char *(*vsnprintf)(int,char*,const char*,va_list);
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
};
/*
** The following macros redefine the API routines so that they are
** redirected throught the global sqlite3_api structure.
**
** This header file is also used by the loadext.c source file
** (part of the main SQLite library - not an extension) so that
** it can get access to the sqlite3_api_routines structure
** definition. But the main library does not want to redefine
** the API. So the redefinition macros are only valid if the
** SQLITE_CORE macros is undefined.
*/
#ifndef SQLITE_CORE
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
#endif
#define sqlite3_bind_blob sqlite3_api->bind_blob
#define sqlite3_bind_double sqlite3_api->bind_double
#define sqlite3_bind_int sqlite3_api->bind_int
#define sqlite3_bind_int64 sqlite3_api->bind_int64
#define sqlite3_bind_null sqlite3_api->bind_null
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
#define sqlite3_bind_text sqlite3_api->bind_text
#define sqlite3_bind_text16 sqlite3_api->bind_text16
#define sqlite3_bind_value sqlite3_api->bind_value
#define sqlite3_busy_handler sqlite3_api->busy_handler
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
#define sqlite3_changes sqlite3_api->changes
#define sqlite3_close sqlite3_api->close
#define sqlite3_collation_needed sqlite3_api->collation_needed
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
#define sqlite3_column_blob sqlite3_api->column_blob
#define sqlite3_column_bytes sqlite3_api->column_bytes
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
#define sqlite3_column_count sqlite3_api->column_count
#define sqlite3_column_database_name sqlite3_api->column_database_name
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
#define sqlite3_column_decltype sqlite3_api->column_decltype
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
#define sqlite3_column_double sqlite3_api->column_double
#define sqlite3_column_int sqlite3_api->column_int
#define sqlite3_column_int64 sqlite3_api->column_int64
#define sqlite3_column_name sqlite3_api->column_name
#define sqlite3_column_name16 sqlite3_api->column_name16
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
#define sqlite3_column_table_name sqlite3_api->column_table_name
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
#define sqlite3_column_text sqlite3_api->column_text
#define sqlite3_column_text16 sqlite3_api->column_text16
#define sqlite3_column_type sqlite3_api->column_type
#define sqlite3_column_value sqlite3_api->column_value
#define sqlite3_commit_hook sqlite3_api->commit_hook
#define sqlite3_complete sqlite3_api->complete
#define sqlite3_complete16 sqlite3_api->complete16
#define sqlite3_create_collation sqlite3_api->create_collation
#define sqlite3_create_collation16 sqlite3_api->create_collation16
#define sqlite3_create_function sqlite3_api->create_function
#define sqlite3_create_function16 sqlite3_api->create_function16
#define sqlite3_create_module sqlite3_api->create_module
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
#define sqlite3_data_count sqlite3_api->data_count
#define sqlite3_db_handle sqlite3_api->db_handle
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
#define sqlite3_errcode sqlite3_api->errcode
#define sqlite3_errmsg sqlite3_api->errmsg
#define sqlite3_errmsg16 sqlite3_api->errmsg16
#define sqlite3_exec sqlite3_api->exec
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_expired sqlite3_api->expired
#endif
#define sqlite3_finalize sqlite3_api->finalize
#define sqlite3_free sqlite3_api->free
#define sqlite3_free_table sqlite3_api->free_table
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
#define sqlite3_get_table sqlite3_api->get_table
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_global_recover sqlite3_api->global_recover
#endif
#define sqlite3_interrupt sqlite3_api->interruptx
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
#define sqlite3_libversion sqlite3_api->libversion
#define sqlite3_libversion_number sqlite3_api->libversion_number
#define sqlite3_malloc sqlite3_api->malloc
#define sqlite3_mprintf sqlite3_api->mprintf
#define sqlite3_open sqlite3_api->open
#define sqlite3_open16 sqlite3_api->open16
#define sqlite3_prepare sqlite3_api->prepare
#define sqlite3_prepare16 sqlite3_api->prepare16
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_profile sqlite3_api->profile
#define sqlite3_progress_handler sqlite3_api->progress_handler
#define sqlite3_realloc sqlite3_api->realloc
#define sqlite3_reset sqlite3_api->reset
#define sqlite3_result_blob sqlite3_api->result_blob
#define sqlite3_result_double sqlite3_api->result_double
#define sqlite3_result_error sqlite3_api->result_error
#define sqlite3_result_error16 sqlite3_api->result_error16
#define sqlite3_result_int sqlite3_api->result_int
#define sqlite3_result_int64 sqlite3_api->result_int64
#define sqlite3_result_null sqlite3_api->result_null
#define sqlite3_result_text sqlite3_api->result_text
#define sqlite3_result_text16 sqlite3_api->result_text16
#define sqlite3_result_text16be sqlite3_api->result_text16be
#define sqlite3_result_text16le sqlite3_api->result_text16le
#define sqlite3_result_value sqlite3_api->result_value
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
#define sqlite3_snprintf sqlite3_api->snprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
#define sqlite3_total_changes sqlite3_api->total_changes
#define sqlite3_trace sqlite3_api->trace
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
#endif
#define sqlite3_update_hook sqlite3_api->update_hook
#define sqlite3_user_data sqlite3_api->user_data
#define sqlite3_value_blob sqlite3_api->value_blob
#define sqlite3_value_bytes sqlite3_api->value_bytes
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
#define sqlite3_value_double sqlite3_api->value_double
#define sqlite3_value_int sqlite3_api->value_int
#define sqlite3_value_int64 sqlite3_api->value_int64
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
#define sqlite3_value_text sqlite3_api->value_text
#define sqlite3_value_text16 sqlite3_api->value_text16
#define sqlite3_value_text16be sqlite3_api->value_text16be
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
#define sqlite3_blob_close sqlite3_api->blob_close
#define sqlite3_blob_open sqlite3_api->blob_open
#define sqlite3_blob_read sqlite3_api->blob_read
#define sqlite3_blob_write sqlite3_api->blob_write
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
#define sqlite3_file_control sqlite3_api->file_control
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
#define sqlite3_memory_used sqlite3_api->memory_used
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
#define sqlite3_mutex_free sqlite3_api->mutex_free
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
#define sqlite3_mutex_try sqlite3_api->mutex_try
#define sqlite3_open_v2 sqlite3_api->open_v2
#define sqlite3_release_memory sqlite3_api->release_memory
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
#define sqlite3_sleep sqlite3_api->sleep
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
#define sqlite3_vfs_find sqlite3_api->vfs_find
#define sqlite3_vfs_register sqlite3_api->vfs_register
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
#define sqlite3_result_error_code sqlite3_api->result_error_code
#define sqlite3_test_control sqlite3_api->test_control
#define sqlite3_randomness sqlite3_api->randomness
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
#define sqlite3_limit sqlite3_api->limit
#define sqlite3_next_stmt sqlite3_api->next_stmt
#define sqlite3_sql sqlite3_api->sql
#define sqlite3_status sqlite3_api->status
#define sqlite3_backup_finish sqlite3_api->backup_finish
#define sqlite3_backup_init sqlite3_api->backup_init
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
#define sqlite3_backup_step sqlite3_api->backup_step
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
#define sqlite3_db_config sqlite3_api->db_config
#define sqlite3_db_mutex sqlite3_api->db_mutex
#define sqlite3_db_status sqlite3_api->db_status
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
#define sqlite3_log sqlite3_api->log
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
#define sqlite3_sourceid sqlite3_api->sourceid
#define sqlite3_stmt_status sqlite3_api->stmt_status
#define sqlite3_strnicmp sqlite3_api->strnicmp
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
#define sqlite3_wal_hook sqlite3_api->wal_hook
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
#define sqlite3_vtab_config sqlite3_api->vtab_config
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
/* Version 3.7.16 and later */
#define sqlite3_close_v2 sqlite3_api->close_v2
#define sqlite3_db_filename sqlite3_api->db_filename
#define sqlite3_db_readonly sqlite3_api->db_readonly
#define sqlite3_db_release_memory sqlite3_api->db_release_memory
#define sqlite3_errstr sqlite3_api->errstr
#define sqlite3_stmt_busy sqlite3_api->stmt_busy
#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
#define sqlite3_stricmp sqlite3_api->stricmp
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
#define sqlite3_uri_int64 sqlite3_api->uri_int64
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
#endif /* SQLITE_CORE */
#ifndef SQLITE_CORE
/* This case when the file really is being compiled as a loadable
** extension */
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
# define SQLITE_EXTENSION_INIT3 \
extern const sqlite3_api_routines *sqlite3_api;
#else
/* This case when the file is being statically linked into the
** application */
# define SQLITE_EXTENSION_INIT1 /*no-op*/
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
# define SQLITE_EXTENSION_INIT3 /*no-op*/
#endif
#endif /* _SQLITE3EXT_H_ */

View File

@ -0,0 +1,3 @@
module PostboxPrivate {
export *
}

View File

@ -0,0 +1,159 @@
import UIKit
import XCTest
import Postbox
class TestParent: Coding, Equatable {
var parentInt32: Int32
required init(decoder: Decoder) {
self.parentInt32 = decoder.decodeInt32ForKey("parentInt32")
}
init(parentInt32: Int32) {
self.parentInt32 = parentInt32
}
func encode(encoder: Encoder) {
encoder.encodeInt32(self.parentInt32, forKey: "parentInt32")
}
}
class TestObject: TestParent {
var int32: Int32
var int64: Int64
var double: Double
var string: String
var int32Array: [Int32]
var int64Array: [Int64]
required init(decoder: Decoder) {
self.int32 = decoder.decodeInt32ForKey("int32")
self.int64 = decoder.decodeInt64ForKey("int64")
self.double = decoder.decodeDoubleForKey("double")
self.string = decoder.decodeStringForKey("string")
self.int32Array = decoder.decodeInt32ArrayForKey("int32Array")
self.int64Array = decoder.decodeInt64ArrayForKey("int64Array")
super.init(decoder: decoder)
}
init(parentInt32: Int32, int32: Int32, int64: Int64, double: Double, string: String, int32Array: [Int32], int64Array: [Int64]) {
self.int32 = int32
self.int64 = int64
self.double = double
self.string = string
self.int32Array = int32Array
self.int64Array = int64Array
super.init(parentInt32: parentInt32)
}
override func encode(encoder: Encoder) {
encoder.encodeInt32(self.int32, forKey: "int32")
encoder.encodeInt64(self.int64, forKey: "int64")
encoder.encodeDouble(self.double, forKey: "double")
encoder.encodeString(self.string, forKey: "string")
encoder.encodeInt32Array(self.int32Array, forKey: "int32Array")
encoder.encodeInt64Array(self.int64Array, forKey: "int64Array")
super.encode(encoder)
}
}
class TestKey: Coding, Hashable {
let value: Int
required init(decoder: Decoder) {
self.value = Int(decoder.decodeInt32ForKey("value"))
}
init(value: Int) {
self.value = value
}
func encode(encoder: Encoder) {
encoder.encodeInt32(Int32(self.value), forKey: "value")
}
var hashValue: Int {
get {
return self.value
}
}
}
func ==(lhs: TestObject, rhs: TestObject) -> Bool {
return lhs.int32 == rhs.int32 &&
lhs.int64 == rhs.int64 &&
lhs.double == rhs.double &&
lhs.string == rhs.string &&
lhs.int32Array == rhs.int32Array &&
lhs.int64Array == rhs.int64Array &&
lhs.parentInt32 == rhs.parentInt32
}
func ==(lhs: TestParent, rhs: TestParent) -> Bool {
return lhs.parentInt32 == rhs.parentInt32
}
func ==(lhs: TestKey, rhs: TestKey) -> Bool {
return lhs.value == rhs.value
}
class SerializationTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testExample() {
declareEncodable(TestParent.self, { TestParent(decoder: $0) })
declareEncodable(TestObject.self, { TestObject(decoder: $0) })
declareEncodable(TestKey.self, { TestKey(decoder: $0) })
let encoder = Encoder()
encoder.encodeInt32(12345, forKey: "a")
encoder.encodeInt64(Int64(12345), forKey: "b")
encoder.encodeBool(true, forKey: "c")
encoder.encodeString("test", forKey: "d")
let before = TestObject(parentInt32: 100, int32: 12345, int64: 67890, double: 1.23456, string: "test", int32Array: [1, 2, 3, 4, 5], int64Array: [6, 7, 8, 9, 0])
encoder.encodeObject(before, forKey: "e")
encoder.encodeInt32Array([1, 2, 3, 4], forKey: "f")
encoder.encodeInt64Array([1, 2, 3, 4], forKey: "g")
let beforeArray: [TestParent] = [TestObject(parentInt32: 1000, int32: 12345, int64: 67890, double: 1.23456, string: "test", int32Array: [1, 2, 3, 4, 5], int64Array: [6, 7, 8, 9, 0]), TestParent(parentInt32: 2000)]
encoder.encodeObjectArray(beforeArray, forKey: "h")
let beforeDictionary: [TestKey : TestParent] = [
TestKey(value: 1): TestObject(parentInt32: 1000, int32: 12345, int64: 67890, double: 1.23456, string: "test", int32Array: [1, 2, 3, 4, 5], int64Array: [6, 7, 8, 9, 0]),
TestKey(value: 2): TestParent(parentInt32: 2000)
]
encoder.encodeObjectDictionary(beforeDictionary, forKey: "i")
let decoder = Decoder(buffer: encoder.makeReadBufferAndReset())
let afterDictionary = decoder.decodeObjectDictionaryForKey("i") as [TestKey : TestParent]
XCTAssert(afterDictionary == beforeDictionary, "object dictionary failed")
let afterArray = decoder.decodeObjectArrayForKey("h") as [TestParent]
XCTAssert(afterArray == beforeArray, "object array failed")
XCTAssert(decoder.decodeInt64ArrayForKey("g") == [1, 2, 3, 4], "int64 array failed")
XCTAssert(decoder.decodeInt32ArrayForKey("f") == [1, 2, 3, 4], "int32 array failed")
if let after = decoder.decodeObjectForKey("e") as? TestObject {
XCTAssert(after == before, "object failed")
} else {
XCTFail("object failed")
}
XCTAssert(decoder.decodeStringForKey("d") == "test", "string failed")
XCTAssert(decoder.decodeBoolForKey("c"), "bool failed")
XCTAssert(decoder.decodeInt64ForKey("b") == Int64(12345), "int64 failed")
XCTAssert(decoder.decodeInt32ForKey("a") == 12345, "int32 failed")
}
}

View File

@ -1,36 +1,663 @@
//
// PostboxTests.swift
// PostboxTests
//
// Created by Peter on 10/06/15.
// Copyright (c) 2015 Telegram. All rights reserved.
//
import UIKit
import XCTest
import Postbox
enum TestPeerNamespace: PeerId.Namespace {
case User = 0
}
enum TestMessageNamespace: MessageId.Namespace {
case Cloud = 0
case Local = 1
}
enum TestMediaNamespace: MediaId.Namespace {
case Test = 0
}
class TestMessage: Message {
var id: MessageId
var authorId: PeerId
var date: Int32
var text: String
var referencedMediaIds: [MediaId]
var timestamp: Int32 {
return date
}
init(id: MessageId, authorId: PeerId, date: Int32, text: String, referencedMediaIds: [MediaId]) {
self.id = id
self.authorId = authorId
self.date = date
self.text = text
self.referencedMediaIds = referencedMediaIds
}
required init(decoder: Decoder) {
self.id = MessageId(decoder.decodeBytesForKeyNoCopy("id"))
self.authorId = PeerId(decoder.decodeInt64ForKey("authorId"))
self.date = decoder.decodeInt32ForKey("date")
self.text = decoder.decodeStringForKey("text")
self.referencedMediaIds = MediaId.decodeArrayFromBuffer(decoder.decodeBytesForKeyNoCopy("mediaIds"))
}
func encode(encoder: Encoder) {
let buffer = WriteBuffer()
self.id.encodeToBuffer(buffer)
encoder.encodeBytes(buffer, forKey: "id")
buffer.reset()
encoder.encodeInt64(self.authorId.toInt64(), forKey: "authorId")
encoder.encodeInt32(self.date, forKey: "date")
encoder.encodeString(self.text, forKey: "text")
MediaId.encodeArrayToBuffer(self.referencedMediaIds, buffer: buffer)
encoder.encodeBytes(buffer, forKey: "mediaIds")
buffer.reset()
}
}
class TestMedia: Media {
var id: MediaId
init(id: MediaId) {
self.id = id
}
required init(decoder: Decoder) {
self.id = MediaId(decoder.decodeBytesForKeyNoCopy("id"))
}
func encode(encoder: Encoder) {
let buffer = WriteBuffer()
self.id.encodeToBuffer(buffer)
encoder.encodeBytes(buffer, forKey: "id")
}
}
class PostboxTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
XCTAssert(true, "Pass")
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measureBlock() {
// Put the code you want to measure the time of here.
func testAddMessages() {
declareEncodable(TestMessage.self, { TestMessage(decoder: $0) })
declareEncodable(TestMedia.self, { TestMedia(decoder: $0) })
let ownerId = PeerId(namespace: TestPeerNamespace.User.rawValue, id: 1000)
let otherId = PeerId(namespace: TestPeerNamespace.User.rawValue, id: 2000)
let messageNamespace = TestMessageNamespace.Cloud.rawValue
let basePath = "/tmp/postboxtest"
NSFileManager.defaultManager().removeItemAtPath(basePath, error: nil)
let postbox = Postbox(basePath: basePath, ownerId: ownerId, messageNamespaces: [messageNamespace])
postbox.modify { state in
let testMedia = TestMedia(id: MediaId(namespace: TestMediaNamespace.Test.rawValue, id: 1))
for i in 0 ..< 10 {
let messageId = MessageId(peerId: otherId, namespace: messageNamespace, id: Int32(i + 1))
let message = TestMessage(id: messageId, authorId: ownerId, date: Int32(i + 100), text: "\(i)", referencedMediaIds: [testMedia.id])
state.addMessages([message, message], medias: [testMedia])
}
return
}
postbox._dumpTables()
postbox.modify { state in
var messageIds: [MessageId] = []
for i in 0 ..< 5 {
let messageId = MessageId(peerId: otherId, namespace: messageNamespace, id: Int32(i + 1))
messageIds.append(messageId)
}
state.deleteMessagesWithIds(messageIds)
}
postbox._dumpTables();
postbox.modify { state in
var messageIds: [MessageId] = []
for i in 0 ..< 10 {
let messageId = MessageId(peerId: otherId, namespace: messageNamespace, id: Int32(i + 1))
messageIds.append(messageId)
}
state.deleteMessagesWithIds(messageIds)
}
postbox._dumpTables();
}
func testMessageNamespaceViewAddTail() {
let otherId = PeerId(namespace: TestPeerNamespace.User.rawValue, id: 2000)
let view = MutableMessageView(namespaces: [1, 2], count: 3, earlier: [:], messages: [], later: [:])
func message(namespace: Int32, id: Int32, timestamp: Int32) -> Message {
let messageId = MessageId(peerId: otherId, namespace: namespace, id: Int32(id))
return TestMessage(id: messageId, authorId: otherId, date: Int32(timestamp), text: "", referencedMediaIds: [])
}
func add(message: Message) {
view.add(message)
println("\(view)\n")
}
/*func assertIds(earlier: Int32?, ids: [Int32], later: Int32?) {
let otherMessages = ids.reverse().map({ id -> Message in
let messageId = MessageId(peerId: otherId, namespace: messageNamespace, id: Int32(id))
let message = TestMessage(id: messageId, authorId: otherId, date: Int32(0), text: "", referencedMediaIds: [])
return message
})
let otherView = MessageNamespaceView(namespace: messageNamespace, messages: otherMessages, earlierId: earlier, laterId: later, count: 2)
XCTAssert(view == otherView, "\(view) != \(otherView)")
}*/
add(message(1, 90, 90))
add(message(2, 70, 70))
add(message(1, 70, 70))
add(message(1, 80, 80))
add(message(2, 100, 100))
add(message(1, 75, 75))
add(message(1, 60, 60))
}
func testMessageNamespaceViewAddMiddle1() {
let otherId = PeerId(namespace: TestPeerNamespace.User.rawValue, id: 2000)
func message(namespace: Int32, id: Int32, timestamp: Int32) -> Message {
let messageId = MessageId(peerId: otherId, namespace: namespace, id: Int32(id))
return TestMessage(id: messageId, authorId: otherId, date: Int32(timestamp), text: "", referencedMediaIds: [])
}
let view = MutableMessageView(namespaces: [1, 2], count: 3, earlier: [1: message(1, 90, 90)], messages: [message(1, 100, 100), message(1, 120, 120), message(1, 140, 140)], later: [1: message(1, 200, 200)])
func add(message: Message) {
view.add(message)
println("\(view)\n")
}
add(message(2, 105, 105))
add(message(2, 150, 150))
add(message(2, 250, 250))
add(message(2, 180, 180))
}
func testMessageNamespaceRemoveTail() {
let otherId = PeerId(namespace: TestPeerNamespace.User.rawValue, id: 2000)
var messages: [Message] = []
func print(messages: [Message]) {
var string = ""
string += "["
var first = true
for message in messages {
if first {
first = false
} else {
string += ", "
}
string += "\(message.id.namespace): \(message.id.id)\(message.timestamp)"
}
string += "]"
println(string)
}
let view = MutableMessageView(namespaces: [1, 2], count: 3, earlier: [:], messages: [], later: [:])
func id(namespace: Int32, id: Int32) -> MessageId {
return MessageId(peerId: otherId, namespace: namespace, id: Int32(id))
}
func message(namespace: Int32, id: Int32, timestamp: Int32) -> Message {
let messageId = MessageId(peerId: otherId, namespace: namespace, id: Int32(id))
return TestMessage(id: messageId, authorId: otherId, date: Int32(timestamp), text: "", referencedMediaIds: [])
}
func add(message: Message) {
view.add(message)
println("\(view)")
messages.append(message)
messages.sort({MessageIndex($0) < MessageIndex($1)})
print(messages)
println()
}
func remove(ids: Set<MessageId>) -> MutableMessageView.RemoveContext {
let context = view.remove(ids)
println("\(view)")
messages = messages.filter { !ids.contains($0.id) }
print(messages)
return context
}
func fetchEarlier(messages: [Message])(namespace: MessageId.Namespace, id: MessageId.Id?, count: Int) -> [Message] {
var filtered: [Message] = []
var i = messages.count - 1
while i >= 0 && filtered.count < count {
if messages[i].id.namespace == namespace && (id == nil || messages[i].id.id < id!) {
filtered.append(messages[i])
}
i--
}
return filtered
}
func fetchLater(messages: [Message])(namespace: MessageId.Namespace, id: MessageId.Id?, count: Int) -> [Message] {
var filtered: [Message] = []
var i = 0
while i < messages.count && filtered.count < count {
if messages[i].id.namespace == namespace && (id == nil || messages[i].id.id > id!) {
filtered.append(messages[i])
}
i++
}
return filtered
}
func complete(context: MutableMessageView.RemoveContext) {
view.complete(context, fetchEarlier: fetchEarlier(messages), fetchLater: fetchLater(messages))
println("\(view)\n")
}
add(message(1, 90, 90))
add(message(2, 70, 70))
add(message(1, 70, 70))
add(message(1, 80, 80))
add(message(2, 100, 100))
add(message(1, 75, 75))
add(message(1, 60, 60))
println("remove 1:90, 2:100")
complete(remove([id(1, 90), id(2, 100)]))
println("remove 1:60, 2:70")
complete(remove([id(1, 60), id(2, 70)]))
println("remove 1:80, 2:100")
complete(remove([id(1, 80), id(2, 100)]))
}
func testMessageNamespaceRemoveAllInside() {
let otherId = PeerId(namespace: TestPeerNamespace.User.rawValue, id: 2000)
var messages: [Message] = []
func print(messages: [Message]) {
var string = ""
string += "["
var first = true
for message in messages {
if first {
first = false
} else {
string += ", "
}
string += "\(message.id.namespace): \(message.id.id)\(message.timestamp)"
}
string += "]"
println(string)
}
let view = MutableMessageView(namespaces: [1, 2], count: 3, earlier: [:], messages: [], later: [:])
func id(namespace: Int32, id: Int32) -> MessageId {
return MessageId(peerId: otherId, namespace: namespace, id: Int32(id))
}
func message(namespace: Int32, id: Int32, timestamp: Int32) -> Message {
let messageId = MessageId(peerId: otherId, namespace: namespace, id: Int32(id))
return TestMessage(id: messageId, authorId: otherId, date: Int32(timestamp), text: "", referencedMediaIds: [])
}
func add(message: Message) {
view.add(message)
println("\(view)")
messages.append(message)
messages.sort({MessageIndex($0) < MessageIndex($1)})
print(messages)
println()
}
func remove(ids: Set<MessageId>) -> MutableMessageView.RemoveContext {
let context = view.remove(ids)
println("\(view)")
messages = messages.filter { !ids.contains($0.id) }
print(messages)
return context
}
func fetchEarlier(messages: [Message])(namespace: MessageId.Namespace, id: MessageId.Id?, count: Int) -> [Message] {
var filtered: [Message] = []
var i = messages.count - 1
while i >= 0 && filtered.count < count {
if messages[i].id.namespace == namespace && (id == nil || messages[i].id.id < id!) {
filtered.append(messages[i])
}
i--
}
return filtered
}
func fetchLater(messages: [Message])(namespace: MessageId.Namespace, id: MessageId.Id?, count: Int) -> [Message] {
var filtered: [Message] = []
var i = 0
while i < messages.count && filtered.count < count {
if messages[i].id.namespace == namespace && (id == nil || messages[i].id.id > id!) {
filtered.append(messages[i])
}
i++
}
return filtered
}
func complete(context: MutableMessageView.RemoveContext) {
view.complete(context, fetchEarlier: fetchEarlier(messages), fetchLater: fetchLater(messages))
println("\(view)\n")
}
add(message(2, 10, 10))
add(message(2, 20, 20))
add(message(1, 90, 90))
add(message(2, 70, 70))
add(message(1, 70, 70))
add(message(1, 80, 80))
add(message(2, 100, 100))
add(message(1, 75, 75))
add(message(1, 60, 60))
println("remove 2:20, 1:80, 1:90, 2:100")
complete(remove([id(2, 20), id(1, 80), id(1, 90), id(2, 100)]))
}
func testMessageNamespaceRemoveMiddleSome() {
let otherId = PeerId(namespace: TestPeerNamespace.User.rawValue, id: 2000)
var messages: [Message] = []
func print(messages: [Message]) {
var string = ""
string += "["
var first = true
for message in messages {
if first {
first = false
} else {
string += ", "
}
string += "\(message.id.namespace): \(message.id.id)\(message.timestamp)"
}
string += "]"
println(string)
}
func id(namespace: Int32, id: Int32) -> MessageId {
return MessageId(peerId: otherId, namespace: namespace, id: Int32(id))
}
func message(namespace: Int32, id: Int32, timestamp: Int32) -> Message {
let messageId = MessageId(peerId: otherId, namespace: namespace, id: Int32(id))
return TestMessage(id: messageId, authorId: otherId, date: Int32(timestamp), text: "", referencedMediaIds: [])
}
messages = [message(2, 1, 1), message(2, 2, 2), message(1, 98, 98), message(1, 99, 99), message(1, 100, 100), message(2, 101, 101), message(1, 102, 102), message(1, 103, 103), message(1, 104, 104), message(1, 105, 105), message(2, 200, 200), message(2, 300, 300)]
let view = MutableMessageView(namespaces: [1, 2], count: 3, earlier: [1: message(1, 99, 99), 2: message(2, 2, 2)], messages: [message(1, 100, 100), message(2, 101, 101), message(1, 102, 102)], later: [1: message(1, 103, 103), 2: message(2, 200, 200)])
func add(message: Message) {
view.add(message)
println("\(view)")
messages.append(message)
messages.sort({MessageIndex($0) < MessageIndex($1)})
print(messages)
println()
}
func remove(ids: Set<MessageId>) -> MutableMessageView.RemoveContext {
let context = view.remove(ids)
println("\(view)")
messages = messages.filter { !ids.contains($0.id) }
print(messages)
return context
}
func fetchEarlier(messages: [Message])(namespace: MessageId.Namespace, id: MessageId.Id?, count: Int) -> [Message] {
var filtered: [Message] = []
var i = messages.count - 1
while i >= 0 && filtered.count < count {
if messages[i].id.namespace == namespace && (id == nil || messages[i].id.id < id!) {
filtered.append(messages[i])
}
i--
}
return filtered
}
func fetchLater(messages: [Message])(namespace: MessageId.Namespace, id: MessageId.Id?, count: Int) -> [Message] {
var filtered: [Message] = []
var i = 0
while i < messages.count && filtered.count < count {
if messages[i].id.namespace == namespace && (id == nil || messages[i].id.id > id!) {
filtered.append(messages[i])
}
i++
}
return filtered
}
func complete(context: MutableMessageView.RemoveContext) {
view.complete(context, fetchEarlier: fetchEarlier(messages), fetchLater: fetchLater(messages))
println("\(view)\n")
}
print(messages)
println("\(view)")
println("remove 1:100, 2:101")
complete(remove([id(1, 100), id(2, 101)]))
}
func testMessageNamespaceRemoveMiddleAllInside() {
let otherId = PeerId(namespace: TestPeerNamespace.User.rawValue, id: 2000)
var messages: [Message] = []
func print(messages: [Message]) {
var string = ""
string += "["
var first = true
for message in messages {
if first {
first = false
} else {
string += ", "
}
string += "\(message.id.namespace): \(message.id.id)\(message.timestamp)"
}
string += "]"
println(string)
}
func id(namespace: Int32, id: Int32) -> MessageId {
return MessageId(peerId: otherId, namespace: namespace, id: Int32(id))
}
func message(namespace: Int32, id: Int32, timestamp: Int32) -> Message {
let messageId = MessageId(peerId: otherId, namespace: namespace, id: Int32(id))
return TestMessage(id: messageId, authorId: otherId, date: Int32(timestamp), text: "", referencedMediaIds: [])
}
messages = [message(2, 1, 1), message(2, 2, 2), message(1, 98, 98), message(1, 99, 99), message(1, 100, 100), message(2, 101, 101), message(1, 102, 102), message(1, 103, 103), message(1, 104, 104), message(1, 105, 105), message(2, 200, 200), message(2, 300, 300)]
let view = MutableMessageView(namespaces: [1, 2], count: 3, earlier: [1: message(1, 99, 99), 2: message(2, 2, 2)], messages: [message(1, 100, 100), message(2, 101, 101), message(1, 102, 102)], later: [1: message(1, 103, 103), 2: message(2, 200, 200)])
func add(message: Message) {
view.add(message)
println("\(view)")
messages.append(message)
messages.sort({MessageIndex($0) < MessageIndex($1)})
print(messages)
println()
}
func remove(ids: Set<MessageId>) -> MutableMessageView.RemoveContext {
let context = view.remove(ids)
println("\(view)")
messages = messages.filter { !ids.contains($0.id) }
print(messages)
return context
}
func fetchEarlier(messages: [Message])(namespace: MessageId.Namespace, id: MessageId.Id?, count: Int) -> [Message] {
var filtered: [Message] = []
var i = messages.count - 1
while i >= 0 && filtered.count < count {
if messages[i].id.namespace == namespace && (id == nil || messages[i].id.id < id!) {
filtered.append(messages[i])
}
i--
}
return filtered
}
func fetchLater(messages: [Message])(namespace: MessageId.Namespace, id: MessageId.Id?, count: Int) -> [Message] {
var filtered: [Message] = []
var i = 0
while i < messages.count && filtered.count < count {
if messages[i].id.namespace == namespace && (id == nil || messages[i].id.id > id!) {
filtered.append(messages[i])
}
i++
}
return filtered
}
func complete(context: MutableMessageView.RemoveContext) {
view.complete(context, fetchEarlier: fetchEarlier(messages), fetchLater: fetchLater(messages))
println("\(view)\n")
}
print(messages)
println("\(view)\n")
println("remove 1:100, 2:101, 1: 102")
complete(remove([id(1, 100), id(2, 101), id(1, 102)]))
}
func testViewTail() {
declareEncodable(TestMessage.self, { TestMessage(decoder: $0) })
declareEncodable(TestMedia.self, { TestMedia(decoder: $0) })
let ownerId = PeerId(namespace: TestPeerNamespace.User.rawValue, id: 1000)
let otherId = PeerId(namespace: TestPeerNamespace.User.rawValue, id: 2000)
let messageNamespace = TestMessageNamespace.Cloud.rawValue
let basePath = "/tmp/postboxtest"
NSFileManager.defaultManager().removeItemAtPath(basePath, error: nil)
let postbox = Postbox(basePath: basePath, ownerId: ownerId, messageNamespaces: [messageNamespace])
postbox.modify { state in
let testMedia = TestMedia(id: MediaId(namespace: TestMediaNamespace.Test.rawValue, id: 1))
for i in 0 ..< 10 {
let messageId = MessageId(peerId: otherId, namespace: messageNamespace, id: Int32(i + 1))
let message = TestMessage(id: messageId, authorId: ownerId, date: Int32(i + 100), text: "\(i)", referencedMediaIds: [testMedia.id])
state.addMessages([message, message], medias: [testMedia])
}
return
}
postbox.tailMessageViewForPeerId(otherId, count: 4).start(next: { next in
println(next)
})
postbox.modify { state in
let testMedia = TestMedia(id: MediaId(namespace: TestMediaNamespace.Test.rawValue, id: 1))
for i in 10 ..< 15 {
let messageId = MessageId(peerId: otherId, namespace: messageNamespace, id: Int32(i + 1))
let message = TestMessage(id: messageId, authorId: ownerId, date: Int32(i + 100), text: "\(i)", referencedMediaIds: [testMedia.id])
state.addMessages([message, message], medias: [testMedia])
}
return
}
postbox._sync()
}
func testViewAround() {
declareEncodable(TestMessage.self, { TestMessage(decoder: $0) })
declareEncodable(TestMedia.self, { TestMedia(decoder: $0) })
let ownerId = PeerId(namespace: TestPeerNamespace.User.rawValue, id: 1000)
let otherId = PeerId(namespace: TestPeerNamespace.User.rawValue, id: 2000)
let messageNamespaceCloud = TestMessageNamespace.Cloud.rawValue
let messageNamespaceLocal = TestMessageNamespace.Local.rawValue
let basePath = "/tmp/postboxtest"
NSFileManager.defaultManager().removeItemAtPath(basePath, error: nil)
let postbox = Postbox(basePath: basePath, ownerId: ownerId, messageNamespaces: [messageNamespaceCloud, messageNamespaceLocal])
postbox.modify { state in
let testMedia = TestMedia(id: MediaId(namespace: TestMediaNamespace.Test.rawValue, id: 1))
for i in 0 ..< 10 {
let messageId = MessageId(peerId: otherId, namespace: messageNamespaceCloud, id: Int32(i + 1))
let message = TestMessage(id: messageId, authorId: ownerId, date: Int32(i + 100), text: "\(i)", referencedMediaIds: [testMedia.id])
state.addMessages([message, message], medias: [testMedia])
}
for i in 10 ..< 12 {
let messageId = MessageId(peerId: otherId, namespace: messageNamespaceLocal, id: Int32(i + 1))
let message = TestMessage(id: messageId, authorId: ownerId, date: Int32(i + 100), text: "\(i)", referencedMediaIds: [testMedia.id])
state.addMessages([message, message], medias: [testMedia])
}
return
}
var i = 1000
postbox.aroundMessageViewForPeerId(otherId, id: MessageId(peerId: otherId, namespace: messageNamespaceCloud, id: Int32(i + 1)), count: 3).start(next: { next in
println(next)
})
postbox.modify { state in
let testMedia = TestMedia(id: MediaId(namespace: TestMediaNamespace.Test.rawValue, id: 1))
for i in 10 ..< 15 {
let messageId = MessageId(peerId: otherId, namespace: messageNamespaceCloud, id: Int32(i + 1))
let message = TestMessage(id: messageId, authorId: ownerId, date: Int32(i + 100), text: "\(i)", referencedMediaIds: [testMedia.id])
state.addMessages([message, message], medias: [testMedia])
}
return
}
postbox._sync()
}
}

@ -0,0 +1 @@
Subproject commit fde8c3391b265eb34b6407e3665160fb981b6857