Permalink
Browse files

Move BSON parser to separate repository

  • Loading branch information...
1 parent 794825c commit a70e7fe70ccfe2607504fb8e0ccd9754cebb1f25 @khueue committed Sep 3, 2012
View
3 .gitignore
@@ -6,7 +6,4 @@ Icon?
._*
.Spotlight-V100
.Trashes
-
-lib/*
*.txt
-private/*
View
6 Guardfile
@@ -3,10 +3,6 @@
# Tests can be run manually by a simple `make`.
guard :shell do
watch /.*/ do |m|
- if m[0] =~ /^lib/
- # Don't trigger on dynamically generated files.
- else
- system "make"
- end
+ system "make"
end
end
View
39 Makefile
@@ -1,42 +1,19 @@
-PROLOG = swipl -O
-PROLOG_LD = swipl-ld
-CC = gcc
-FLAGS = -shared -fPIC -O4 -Wall -Wextra -cc-options,-ansi,-pedantic
+PROLOG = swipl -O
.PHONY: all
-all: compile test
+all: test
.PHONY: test
-test: compile
+test:
@ echo "--- Run tests and exit ..."
- time $(PROLOG) -s load -g test -t halt
+ time $(PROLOG) -s load -g prolongo_test -t halt
.PHONY: cov
-cov: compile
+cov:
@ echo "--- Run tests, print test coverage and exit ..."
- $(PROLOG) -s load -g cov -t halt
+ $(PROLOG) -s load -g prolongo_cov -t halt
.PHONY: repl
-repl: compile
+repl:
@ echo "--- Load and enter REPL ..."
- $(PROLOG) -s load -g repl
-
-.PHONY: compile
-compile: setup lib/bson_bits
-
-# Generic name (not sure what file extensions different systems use).
-lib/bson_bits: ext/bson_bits.c Makefile
- @ echo "--- Compile foreign library 'bson_bits' ..."
- rm -f $@
- $(PROLOG_LD) -o $@.dylib ext/bson_bits.c $(FLAGS) -cc $(CC)
- mv $@.dylib $@
-
-.PHONY: setup
-setup: lib
-
-lib:
- mkdir -p lib
-
-.PHONY: clean
-clean:
- rm -rf lib/*
+ $(PROLOG) -s load -g prolongo_repl
View
40 README.md
@@ -1,15 +1,14 @@
# MongoDB Driver for Prolog
-## Todo
-
- * Move BSON to separate repository (figure out how to load it properly).
- * Reduce amount of arguments to CRUD predicates (start with update?).
- * Make BSON exceptions more idiomatic: bson_error(Desc, EnvList).
+A MongoDB driver compatible with SWI-Prolog that implements basic CRUD
+functionality. Several things have yet to be implemented (authentication,
+GridFS, etc.), but the driver can be used for simple use-cases.
## Release History
### Version 2.0.0 (not yet released)
+ * BSON parser is now an external dependency (separate repository).
* Updated BSON parser to handle new binary 'uuid' subtype.
* Rewritten exception handling (not done yet XXX).
* Fix buggy hex_bytes/2 (used when handling object_id).
@@ -27,10 +26,31 @@
* Fix issue #1 ("Two tests failing on Swi-Prolog 6.0.2").
* Add runnable example program (simple todo).
+## License
+
+Licensed under the MIT license which can be found in the file
+`LICENSE` in the project root.
+
+## Todo
+
+ * Reduce amount of arguments to CRUD predicates.
+
## Usage
+ 1. Clone the BSON parser found at <https://github.com/khueue/prolog-bson>
+ and compile it.
+ 2. Clone prolongo.
+ 3. Edit the path to the BSON loader script found in `load.pl`. The path
+ should be relative to prolongo's root (so you don't have to edit
+ anything if you clone both BSON and prolongo into the same parent
+ folder).
+ 4. Run `make` to run the tests (will also run the BSON tests). Some
+ of the tests require a MongoDB instance running on localhost on the
+ default port.
+ 5. See the example below for usage in your application.
+
Clone the repository and run `make` to compile the necessary C libraries
-and run the test suite. Part of the test suite requires a MongoDB instance
+and run the test suite. Test suite requires a MongoDB instance
running on localhost on the default port. See the example app below, and
the tests (*.plt) in the src folder for usage examples.
@@ -146,16 +166,8 @@ localhost, then go:
## Dependencies
* SWI-Prolog (tested on Mac OS X using SWI 6.0.2)
- * Autoloading must be turned on (default).
- * ANSI C compiler (modify Makefile if not GCC) (tested on Mac OS X
- using GCC and Clang)
* MongoDB (tested on Mac OS X using MongoDB 2.2.0)
-## License
-
-Licensed under the MIT license which can be found in the file
-`LICENSE` in the project root.
-
## Coding Guidelines
* Use empty imports (use_module(mymodule, [])) in order to not
View
235 ext/bson_bits.c
@@ -1,235 +0,0 @@
-/**
- * Bit-packing routines used by the Prolog BSON parser.
- *
- * These functions do no error-checking whatsoever.
- */
-
-#include <SWI-Prolog.h>
-#include <stdint.h>
-
-/**
- * Get the integer from a term.
- */
-static int
-get_int(term_t t)
-{
- int val;
- int rc;
- (void)rc;
- rc = PL_get_integer(t, &val);
- return val;
-}
-
-/**
- * Fill a term with a byte.
- */
-static void
-set_int(term_t t, unsigned char byte)
-{
- int rc;
- (void)rc;
- rc = PL_unify_integer(t, byte);
-}
-
-/**
- * foreign_float_to_bytes(
- * +Float,
- * ?Byte0, ?Byte1, ?Byte2, ?Byte3,
- * ?Byte4, ?Byte5, ?Byte6, ?Byte7) is semidet.
- *
- * True if Float is the floating point number represented by the
- * consecutive bytes Byte0..Byte7 interpreted as a 64-bit
- * IEEE 754 double.
- */
-static foreign_t
-double_to_bytes8(
- term_t float_in,
- term_t b0, term_t b1, term_t b2, term_t b3,
- term_t b4, term_t b5, term_t b6, term_t b7)
-{
- double val;
- unsigned char *byte = (unsigned char *)&val;
- int rc;
- (void)rc;
-
- rc = PL_get_float(float_in, &val);
-
- set_int(b0, byte[0]);
- set_int(b1, byte[1]);
- set_int(b2, byte[2]);
- set_int(b3, byte[3]);
- set_int(b4, byte[4]);
- set_int(b5, byte[5]);
- set_int(b6, byte[6]);
- set_int(b7, byte[7]);
-
- PL_succeed;
-}
-
-/**
- * foreign_bytes_to_float(
- * +Byte0, +Byte1, +Byte2, +Byte3,
- * +Byte4, +Byte5, +Byte6, +Byte7,
- * ?Float) is semidet.
- *
- * True if Float is the floating point number represented by the
- * consecutive bytes Byte0..Byte7 interpreted as a 64-bit
- * IEEE 754 double.
- */
-static foreign_t
-bytes8_to_double(
- term_t b0, term_t b1, term_t b2, term_t b3,
- term_t b4, term_t b5, term_t b6, term_t b7,
- term_t float_out)
-{
- double val;
- unsigned char *byte = (unsigned char *)&val;
-
- byte[0] = get_int(b0);
- byte[1] = get_int(b1);
- byte[2] = get_int(b2);
- byte[3] = get_int(b3);
- byte[4] = get_int(b4);
- byte[5] = get_int(b5);
- byte[6] = get_int(b6);
- byte[7] = get_int(b7);
-
- return PL_unify_float(float_out, val);
-}
-
-/**
- * foreign_integer_to_bytes(
- * +Integer,
- * ?Byte0, ?Byte1, ?Byte2, ?Byte3) is semidet.
- *
- * True if Integer is the integer represented by the consecutive
- * bytes Byte0..Byte3 interpreted as a signed 32-bit
- * little-endian integer.
- */
-static foreign_t
-int32_to_bytes4(
- term_t int32_in,
- term_t b0, term_t b1, term_t b2, term_t b3)
-{
- int32_t val;
- unsigned char *byte = (unsigned char *)&val;
- int rc;
- (void)rc;
-
- rc = PL_get_integer(int32_in, &val);
-
- set_int(b0, byte[0]);
- set_int(b1, byte[1]);
- set_int(b2, byte[2]);
- set_int(b3, byte[3]);
-
- PL_succeed;
-}
-
-/**
- * foreign_bytes_to_integer(
- * +Byte0, +Byte1, +Byte2, +Byte3,
- * ?Integer) is semidet.
- *
- * True if Integer is the integer represented by the consecutive
- * bytes Byte0..Byte3 interpreted as a signed 32-bit
- * little-endian integer.
- */
-static foreign_t
-bytes4_to_int32(
- term_t b0, term_t b1, term_t b2, term_t b3,
- term_t int32_out)
-{
- int32_t val;
- unsigned char *byte = (unsigned char *)&val;
-
- byte[0] = get_int(b0);
- byte[1] = get_int(b1);
- byte[2] = get_int(b2);
- byte[3] = get_int(b3);
-
- return PL_unify_integer(int32_out, val);
-}
-
-/**
- * foreign_integer_to_bytes(
- * +Integer,
- * ?Byte0, ?Byte1, ?Byte2, ?Byte3,
- * ?Byte4, ?Byte5, ?Byte6, ?Byte7) is semidet.
- *
- * True if Integer is the integer represented by the consecutive
- * bytes Byte0..Byte7 interpreted as a signed 64-bit
- * little-endian integer.
- */
-static foreign_t
-int64_to_bytes8(
- term_t int64_in,
- term_t b0, term_t b1, term_t b2, term_t b3,
- term_t b4, term_t b5, term_t b6, term_t b7)
-{
- int64_t val;
- unsigned char *byte = (unsigned char *)&val;
- int rc;
- (void)rc;
-
- rc = PL_get_int64(int64_in, &val);
-
- set_int(b0, byte[0]);
- set_int(b1, byte[1]);
- set_int(b2, byte[2]);
- set_int(b3, byte[3]);
- set_int(b4, byte[4]);
- set_int(b5, byte[5]);
- set_int(b6, byte[6]);
- set_int(b7, byte[7]);
-
- PL_succeed;
-}
-
-/**
- * foreign_bytes_to_integer(
- * +Byte0, +Byte1, +Byte2, +Byte3,
- * +Byte4, +Byte5, +Byte6, +Byte7,
- * ?Integer) is semidet.
- *
- * True if Integer is the integer represented by the consecutive
- * bytes Byte0..Byte7 interpreted as a signed 64-bit
- * little-endian integer.
- */
-static foreign_t
-bytes8_to_int64(
- term_t b0, term_t b1, term_t b2, term_t b3,
- term_t b4, term_t b5, term_t b6, term_t b7,
- term_t int64_out)
-{
- int64_t val;
- unsigned char *byte = (unsigned char *)&val;
-
- byte[0] = get_int(b0);
- byte[1] = get_int(b1);
- byte[2] = get_int(b2);
- byte[3] = get_int(b3);
- byte[4] = get_int(b4);
- byte[5] = get_int(b5);
- byte[6] = get_int(b6);
- byte[7] = get_int(b7);
-
- return PL_unify_int64(int64_out, val);
-}
-
-/**
- * Export functions to Prolog. Called implicitly by Prolog's
- * use_foreign_library/1.
- */
-install_t
-install_bson_bits(void)
-{
- PL_register_foreign("foreign_integer_to_bytes", 5, int32_to_bytes4, 0);
- PL_register_foreign("foreign_bytes_to_integer", 5, bytes4_to_int32, 0);
-
- PL_register_foreign("foreign_integer_to_bytes", 9, int64_to_bytes8, 0);
- PL_register_foreign("foreign_bytes_to_integer", 9, bytes8_to_int64, 0);
-
- PL_register_foreign("foreign_float_to_bytes", 9, double_to_bytes8, 0);
- PL_register_foreign("foreign_bytes_to_float", 9, bytes8_to_double, 0);
-}
View
101 load.pl
@@ -1,7 +1,19 @@
-% Acts as an interface to the system. Sets up load paths and provides
-% a predicate for running the test suite.
+% Acts as an interface to the system. Configures load paths, loads external
+% libraries and provides predicates for initiating the system.
-setup_globals :-
+% prolongo_external_library_loader(-RelativePathToLoader) is multi.
+%
+% Facts with paths to external dependencies relative to this project's root.
+% These facts should point to other loader scripts (usually 'load.pl' files)
+% found in the root of the respective project.
+
+prolongo_external_library_loader('/../bson/load.pl').
+
+% prolongo_configure_globals is det.
+%
+% Configures useful globals used throughout the session.
+
+prolongo_configure_globals :-
% For optimized compiles, tests are by default ignored.
set_test_options([load(always)]).
% Try to make everything as UTF-8 as possible.
@@ -11,55 +23,86 @@
% Displays how modules and such are located.
% set_prolog_flag(verbose_file_search, true).
-setup_load_paths :-
+% prolongo_load_external_libraries is det.
+%
+% Loads external load.pl scripts required by this library.
+
+prolongo_load_external_libraries :-
prolog_load_context(directory, Root), % Available only during compilation.
- setup_path(Root, '/lib', foreign),
- setup_path(Root, '/src/misc', misc),
- setup_path(Root, '/src/bson', bson),
- setup_path(Root, '/src/mongo', mongo).
+ prolongo_external_library_loader(Loader),
+ prolongo_load_external_library(Root, Loader),
+ fail. % Loop through all prolongo_external_library_loader/1.
+prolongo_load_external_libraries.
+
+prolongo_load_external_library(Root, RelativePathToLoader) :-
+ atom_concat(Root, RelativePathToLoader, Loader),
+ [Loader].
-setup_path(PathPrefix, PathSuffix, Name) :-
+% prolongo_configure_load_paths is det.
+%
+% Configures internal load paths in preparation of use_module calls.
+
+prolongo_configure_load_paths :-
+ prolog_load_context(directory, Root), % Available only during compilation.
+ prolongo_configure_path(Root, '/src/misc', misc),
+ prolongo_configure_path(Root, '/src', mongo).
+
+prolongo_configure_path(PathPrefix, PathSuffix, Name) :-
atom_concat(PathPrefix, PathSuffix, Path),
asserta(user:file_search_path(Name, Path)).
-:- setup_globals.
-:- setup_load_paths.
+% Set everything up.
+:- prolongo_configure_globals.
+:- prolongo_load_external_libraries.
+:- prolongo_configure_load_paths.
% Simply loading this module claims to speed up phrase, maplist, etc.,
% but I haven't noticed much difference.
% :- use_module(library(apply_macros)).
:- include(misc(common)).
-test :-
- load_project_modules,
- load_project_tests,
- run_test_suite.
-
-repl :-
- load_project_modules,
- load_project_tests.
-
-cov :-
- load_project_modules,
- load_project_tests,
- run_test_suite_with_coverage.
-
-load_project_modules :-
+prolongo_load_project_modules :-
use_module(library(pldoc), []), % Load first to enable comment processing.
use_module(mongo(mongo), []).
-load_project_tests :-
+prolongo_load_project_tests :-
plunit:load_test_files([]).
-run_test_suite :-
+%% prolongo_test is det.
+%
+% Loads everything and runs the test suite.
+
+prolongo_test :-
+ prolongo_load_project_modules,
+ prolongo_load_project_tests,
+ prolongo_run_test_suite.
+
+prolongo_run_test_suite :-
core:format('~n% Run tests ...~n'),
call_cleanup(
plunit:run_tests,
mongo_test_helper:drop_all_test_databases).
-run_test_suite_with_coverage :-
+%% prolongo_cov is det.
+%
+% Loads everything and runs the test suite with coverage analysis.
+
+prolongo_cov :-
+ prolongo_load_project_modules,
+ prolongo_load_project_tests,
+ prolongo_run_test_suite_with_coverage.
+
+prolongo_run_test_suite_with_coverage :-
core:format('~n% Run tests ...~n'),
call_cleanup(
plunit:show_coverage(plunit:run_tests),
mongo_test_helper:drop_all_test_databases).
+
+%% prolongo_repl is det.
+%
+% Loads everything and enters interactive mode.
+
+prolongo_repl :-
+ prolongo_load_project_modules,
+ prolongo_load_project_tests.
View
86 src/bson/bson.pl
@@ -1,86 +0,0 @@
-/** <module> BSON manipulation.
- *
- * BSON document manipulation and conversion to-and-from bytes.
- *
- * @see <http://bsonspec.org/>
- */
-
-:- module(_,
- [
- doc_bytes/2,
- docs_bytes/2,
- version/1,
- spec_version/1
- % And see reexports below.
- ]).
-
-:- reexport(
- [
- bson_doc
- ]).
-
-:- include(misc(common)).
-
-% Internal modules.
-:- use_module(bson_decoder, []).
-:- use_module(bson_encoder, []).
-:- use_module(bson_bits, []).
-:- use_module(bson_unicode, []).
-% :- use_module(bson(bson_format), []). % Useful during dev.
-
-%% version(?Version) is semidet.
-%
-% True if Version is a list representing the major, minor
-% and patch version numbers of this library.
-
-version([0,0,1]).
-
-%% spec_version(?Version) is semidet.
-%
-% True if Version is a list representing the major and minor
-% version numbers of the implemented BSON specification.
-
-spec_version([1,0]).
-
-%% docs_bytes(+Docs, ?Bytes) is semidet.
-%% docs_bytes(?Docs, +Bytes) is semidet.
-%
-% True if Bytes is the flat-list BSON byte-encoding of all the
-% documents in the list Docs.
-%
-% @param Docs is a list of key-value pair lists.
-% @param Bytes is a list of bytes (in 0..255).
-%
-% @throws bson_error(Reason)
-
-docs_bytes(Docs, Bytes) :-
- core:nonvar(Bytes),
- !,
- bson_decoder:bytes_to_docs(Bytes, Docs).
-docs_bytes(Docs, Bytes) :-
- core:nonvar(Docs),
- !,
- bson_encoder:docs_to_bytes(Docs, Bytes).
-docs_bytes(_Docs, _Bytes) :-
- throw(bson_error('at least one arg must be instantiated')).
-
-%% doc_bytes(+Doc, ?Bytes) is semidet.
-%% doc_bytes(?Doc, +Bytes) is semidet.
-%
-% True if Bytes is the BSON byte-encoding of Doc.
-%
-% @param Doc is a list of key-value pairs.
-% @param Bytes is a list of bytes (in 0..255).
-%
-% @throws bson_error(Reason)
-
-doc_bytes(Doc, Bytes) :-
- core:nonvar(Bytes),
- !,
- bson_decoder:bytes_to_doc(Bytes, Doc).
-doc_bytes(Doc, Bytes) :-
- core:nonvar(Doc),
- !,
- bson_encoder:doc_to_bytes(Doc, Bytes).
-doc_bytes(_Doc, _Bytes) :-
- throw(bson_error('at least one arg must be instantiated')).
View
138 src/bson/bson.plt
@@ -1,138 +0,0 @@
-:- include(misc(common)).
-
-:- begin_tests('bson:docs_bytes/2').
-
-test('no docs', [true(Got == Expected)]) :-
- Expected = [],
- Bytes = [],
- bson:docs_bytes(Expected, Bytes),
- bson:docs_bytes(Got, Bytes).
-
-test('complex doc back-and-forth', [true(Got == Expected)]) :-
- Doc =
- [
- k01 - -5.05,
- k02 - åäö_string, % Atoms only (no code lists).
- k03 - [],
- k04 - [k1-v1, k2-v2],
- k05 - [v1,v2,v3],
- k06 - binary(generic,[1,2,3]),
- k07 - binary(function,[1,2,3]),
- k08 - binary(old_generic,[1,2,3]),
- k09 - binary(uuid_old,[1,2,3]),
- k10 - binary(uuid,[1,2,3]),
- k11 - binary(md5,[1,2,3]),
- k12 - binary(user_defined,[1,2,3]),
- k13 - +undefined,
- k14 - object_id('47cc67093475061e3d95369d'),
- k15 - +false,
- k16 - +true,
- k17 - utc(1302354660284),
- k18 - +null,
- k19 - regex('pattern','options'),
- k20 - db_pointer('string','47cc67093475061e3d95369d'),
- k21 - js('code'),
- k22 - symbol(åäö_string), % Just like atoms.
- k23 - js('code',[mappings-doc]),
- k24 - 32,
- k25 - mongostamp(0),
- k26 - 9223372036854775807,
- k27 - +min,
- k28 - +max
- ],
- Expected =
- [
- Doc,
- Doc
- ],
- bson:docs_bytes(Expected, Bytes),
- bson:docs_bytes(Got, Bytes).
-
-:- end_tests('bson:docs_bytes/2').
-
-:- begin_tests('bson:doc_bytes/2').
-
-test('nonvar, nonvar') :-
- Doc =
- [
- hello - 256
- ],
- Bytes =
- [
- 16,0,0,0, % Length of top doc.
- 0x10, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 0,1,0,0, % Int32 data.
- 0 % End of top doc.
- ],
- bson:doc_bytes(Doc, Bytes).
-
-test('nonvar, var', [true(Got == Expected)]) :-
- Doc =
- [
- hello - 256
- ],
- Expected =
- [
- 16,0,0,0, % Length of top doc.
- 0x10, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 0,1,0,0, % Int32 data.
- 0 % End of top doc.
- ],
- bson:doc_bytes(Doc, Got).
-
-test('var, nonvar', [true(Got == Expected)]) :-
- Expected =
- [
- hello - 256
- ],
- Bytes =
- [
- 16,0,0,0, % Length of top doc.
- 0x10, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 0,1,0,0, % Int32 data.
- 0 % End of top doc.
- ],
- bson:doc_bytes(Got, Bytes).
-
-test('var, var', [throws(bson_error(_))]) :-
- bson:doc_bytes(_, _).
-
-test('complex doc back-and-forth', [true(Got == Expected)]) :-
- Expected =
- [
- k01 - -5.05,
- k02 - åäö_string, % Atoms only (no code lists).
- k03 - [],
- k04 - [k1-v1, k2-v2],
- k05 - [v1,v2,v3],
- k06 - binary(generic,[1,2,3]),
- k07 - binary(function,[1,2,3]),
- k08 - binary(old_generic,[1,2,3]),
- k09 - binary(uuid_old,[1,2,3]),
- k10 - binary(uuid,[1,2,3]),
- k11 - binary(md5,[1,2,3]),
- k12 - binary(user_defined,[1,2,3]),
- k13 - +undefined,
- k14 - object_id('47cc67093475061e3d95369d'),
- k15 - +false,
- k16 - +true,
- k17 - utc(1302354660284),
- k18 - +null,
- k19 - regex('pattern','options'),
- k20 - db_pointer('string','47cc67093475061e3d95369d'),
- k21 - js('code'),
- k22 - symbol(åäö_string), % Just like atoms.
- k23 - js('code',[mappings-doc]),
- k24 - 32,
- k25 - mongostamp(0),
- k26 - 9223372036854775807,
- k27 - +min,
- k28 - +max
- ],
- bson:doc_bytes(Expected, Bytes),
- bson:doc_bytes(Got, Bytes).
-
-:- end_tests('bson:doc_bytes/2').
View
130 src/bson/bson_bits.pl
@@ -1,130 +0,0 @@
-/** <module> Low-level bytes-to-number conversions.
- *
- * Note: This module favors little-endian conversions, meaning
- * that big-endian conversions are little-endian with a reverse.
- * This should probably be fixed in future versions.
- */
-
-:- module(_,
- [
- float_bytes/2,
- integer_bytes/4,
- hex_bytes/2,
- fits_in_32_bits/1,
- fits_in_64_bits/1
- ]).
-
-:- include(misc(common)).
-
-:- use_foreign_library(foreign(bson_bits)).
-
-%% float_bytes(+Float, ?Bytes) is semidet.
-%% float_bytes(?Float, +Bytes) is semidet.
-%
-% True if Float is the floating point number represented by
-% the consecutive bytes in Bytes interpreted as a 64-bit
-% IEEE 754 double.
-%
-% Uses C library for actual conversions.
-
-float_bytes(Float, Bytes) :-
- core:nonvar(Bytes),
- Bytes = [B0,B1,B2,B3,B4,B5,B6,B7],
- !,
- foreign_bytes_to_float(B0, B1, B2, B3, B4, B5, B6, B7, Float).
-float_bytes(Float, Bytes) :-
- core:nonvar(Float),
- !,
- Bytes = [B0,B1,B2,B3,B4,B5,B6,B7],
- foreign_float_to_bytes(Float, B0, B1, B2, B3, B4, B5, B6, B7).
-
-%% integer_bytes(+Integer, +NumBytes, +Endian, ?Bytes) is semidet.
-%% integer_bytes(?Integer, +NumBytes, +Endian, +Bytes) is semidet.
-%
-% True if Integer is the signed integer represented by the bytes
-% in Bytes, given NumBytes 4 or 8 and Endian little or big.
-% Results are undefined if Integer cannot fit in NumBytes bytes.
-%
-% Uses C library for actual conversions.
-
-integer_bytes(Integer, NumBytes, Endian, Bytes) :-
- core:nonvar(Integer),
- !,
- integer_to_bytes(Integer, NumBytes, Endian, Bytes).
-integer_bytes(Integer, _NumBytes, Endian, Bytes) :-
- core:nonvar(Bytes),
- !,
- bytes_to_integer(Endian, Bytes, Integer).
-
-integer_to_bytes(Integer, 4, little, [B0,B1,B2,B3]) :- !,
- foreign_integer_to_bytes(Integer, B0, B1, B2, B3).
-
-integer_to_bytes(Integer, 8, little, [B0,B1,B2,B3,B4,B5,B6,B7]) :- !,
- foreign_integer_to_bytes(Integer, B0, B1, B2, B3, B4, B5, B6, B7).
-
-integer_to_bytes(Integer, N, big, Bytes) :- !,
- integer_to_bytes(Integer, N, little, BytesLittle),
- lists:reverse(BytesLittle, Bytes).
-
-bytes_to_integer(little, [B0,B1,B2,B3], Integer) :- !,
- foreign_bytes_to_integer(B0, B1, B2, B3, Integer).
-
-bytes_to_integer(little, [B0,B1,B2,B3,B4,B5,B6,B7], Integer) :- !,
- foreign_bytes_to_integer(B0, B1, B2, B3, B4, B5, B6, B7, Integer).
-
-bytes_to_integer(big, Bytes, Integer) :- !,
- lists:reverse(Bytes, BytesLittle),
- bytes_to_integer(little, BytesLittle, Integer).
-
-%% fits_in_32_bits(+Integer) is semidet.
-%
-% True if Integer can be stored as a signed 32-bit int.
-
-fits_in_32_bits(Integer) :-
- -(2**(32-1)) =< Integer, Integer =< (2**(32-1))-1.
-
-%% fits_in_64_bits(+Integer) is semidet.
-%
-% True if Integer can be stored as a signed 64-bit int.
-
-fits_in_64_bits(Integer) :-
- -(2**(64-1)) =< Integer, Integer =< (2**(64-1))-1.
-
-%% hex_bytes(+Hex, ?Bytes) is semidet.
-%% hex_bytes(?Hex, +Bytes) is semidet.
-%
-% True if Hex is the hexadecimal atom (without leading '0x')
-% represented by the big-endian bytes in Bytes. Hex must have even
-% number of chars (each pair is a byte).
-
-hex_bytes(Hex, Bytes) :-
- core:nonvar(Hex),
- !,
- core:atom_chars(Hex, HexChars),
- hexchars_to_bytes(HexChars, Bytes).
-hex_bytes(Hex, Bytes) :-
- core:nonvar(Bytes),
- !,
- bytes_to_hexchars(Bytes, HexAtoms),
- core:atomic_list_concat(HexAtoms, Hex).
-
-hexchars_to_bytes([], []).
-hexchars_to_bytes([C1,C2|Chars], [Byte|Bytes]) :-
- core:atomic_list_concat(['0x',C1,C2], ByteAsHexAtom),
- core:atom_number(ByteAsHexAtom, Byte),
- hexchars_to_bytes(Chars, Bytes).
-
-bytes_to_hexchars([], []).
-bytes_to_hexchars([Byte|Bytes], [HexPadded|Chars]) :-
- number_to_hex(Byte, Hex),
- left_pad_with_zero(Byte, Hex, HexPadded),
- bytes_to_hexchars(Bytes, Chars).
-
-number_to_hex(Number, HexAtom) :-
- core:format(atom(HexAtom), '~16r', [Number]).
-
-left_pad_with_zero(Number, Hex, Hex) :-
- Number >= 0x10,
- !.
-left_pad_with_zero(_Number, Hex, Padded) :-
- core:atom_concat('0', Hex, Padded).
View
238 src/bson/bson_bits.plt
@@ -1,238 +0,0 @@
-:- include(misc(common)).
-
-:- begin_tests('bson_bits:float_bytes/2').
-
-test('float, bad input, result undefined', [true(Got \== Expected)]) :-
- Expected = bad(input),
- bson_bits:float_bytes(Expected, Bytes),
- bson_bits:float_bytes(Got, Bytes).
-
-test('float, not a float', [true(Got \== Expected)]) :-
- Expected = 0,
- bson_bits:float_bytes(Expected, Bytes),
- bson_bits:float_bytes(Got, Bytes).
-
-test('float, zero', [true(Got == Expected)]) :-
- Expected = 0.0,
- bson_bits:float_bytes(Expected, Bytes),
- bson_bits:float_bytes(Got, Bytes).
-
-test('float, -5.05', [true(Got == Expected)]) :-
- Expected = -5.05,
- bson_bits:float_bytes(Expected, Bytes),
- bson_bits:float_bytes(Got, Bytes).
-
-test('float, 5.05', [true(Got == Expected)]) :-
- Expected = 5.05,
- bson_bits:float_bytes(Expected, Bytes),
- bson_bits:float_bytes(Got, Bytes).
-
-test('float, pi', [true(Got == Expected)]) :-
- Expected is 3.14159,
- bson_bits:float_bytes(Expected, Bytes),
- bson_bits:float_bytes(Got, Bytes).
-
-:- end_tests('bson_bits:float_bytes/2').
-
-:- begin_tests('bson_bits:integer_bytes/4').
-
-test('32-bit, bad input, result undefined', [true(Got \== Expected)]) :-
- Expected = bad(input),
- bson_bits:integer_bytes(Expected, 4, big, Bytes),
- bson_bits:integer_bytes(Got, 4, big, Bytes).
-
-test('32-bit big-endian, zero', [true(Got == Expected)]) :-
- Expected = 0,
- bson_bits:integer_bytes(Expected, 4, big, Bytes),
- bson_bits:integer_bytes(Got, 4, big, Bytes).
-
-test('32-bit big-endian, -1', [true(Got == Expected)]) :-
- Expected = -1,
- bson_bits:integer_bytes(Expected, 4, big, Bytes),
- bson_bits:integer_bytes(Got, 4, big, Bytes).
-
-test('32-bit big-endian, 1', [true(Got == Expected)]) :-
- Expected = 1,
- bson_bits:integer_bytes(Expected, 4, big, Bytes),
- bson_bits:integer_bytes(Got, 4, big, Bytes).
-
-test('32-bit big-endian, verify endian', [true(Got == Expected)]) :-
- Expected = [0,0,0,1],
- bson_bits:integer_bytes(1, 4, big, Got).
-
-test('32-bit big-endian, min', [true(Got == Expected)]) :-
- Expected is -2**31,
- bson_bits:integer_bytes(Expected, 4, big, Bytes),
- bson_bits:integer_bytes(Got, 4, big, Bytes).
-
-test('32-bit big-endian, min-1', [true(Got \== Expected)]) :-
- Expected is -2**31 - 1, % Too low.
- bson_bits:integer_bytes(Expected, 4, big, Bytes),
- bson_bits:integer_bytes(Got, 4, big, Bytes).
-
-test('32-bit big-endian, max', [true(Got == Expected)]) :-
- Expected is 2**31 - 1,
- bson_bits:integer_bytes(Expected, 4, big, Bytes),
- bson_bits:integer_bytes(Got, 4, big, Bytes).
-
-test('32-bit big-endian, max+1', [true(Got \== Expected)]) :-
- Expected is 2**31, % Too high.
- bson_bits:integer_bytes(Expected, 4, big, Bytes),
- bson_bits:integer_bytes(Got, 4, big, Bytes).
-
-% ------------------------------------
-
-test('32-bit little-endian, zero', [true(Got == Expected)]) :-
- Expected = 0,
- bson_bits:integer_bytes(Expected, 4, little, Bytes),
- bson_bits:integer_bytes(Got, 4, little, Bytes).
-
-test('32-bit little-endian, -1', [true(Got == Expected)]) :-
- Expected = -1,
- bson_bits:integer_bytes(Expected, 4, little, Bytes),
- bson_bits:integer_bytes(Got, 4, little, Bytes).
-
-test('32-bit little-endian, 1', [true(Got == Expected)]) :-
- Expected = 1,
- bson_bits:integer_bytes(Expected, 4, little, Bytes),
- bson_bits:integer_bytes(Got, 4, little, Bytes).
-
-test('32-bit little-endian, verify endian', [true(Got == Expected)]) :-
- Expected = [1,0,0,0],
- bson_bits:integer_bytes(1, 4, little, Got).
-
-test('32-bit little-endian, min', [true(Got == Expected)]) :-
- Expected is -2**31,
- bson_bits:integer_bytes(Expected, 4, little, Bytes),
- bson_bits:integer_bytes(Got, 4, little, Bytes).
-
-test('32-bit little-endian, min-1', [true(Got \== Expected)]) :-
- Expected is -2**31 - 1, % Too low.
- bson_bits:integer_bytes(Expected, 4, little, Bytes),
- bson_bits:integer_bytes(Got, 4, little, Bytes).
-
-test('32-bit little-endian, max', [true(Got == Expected)]) :-
- Expected is 2**31 - 1,
- bson_bits:integer_bytes(Expected, 4, little, Bytes),
- bson_bits:integer_bytes(Got, 4, little, Bytes).
-
-test('32-bit little-endian, max+1', [true(Got \== Expected)]) :-
- Expected is 2**31, % Too high.
- bson_bits:integer_bytes(Expected, 4, little, Bytes),
- bson_bits:integer_bytes(Got, 4, little, Bytes).
-
-% ------------------------------------
-
-test('64-bit, bad input, result undefined', [true(Got \== Expected)]) :-
- Expected = bad(input),
- bson_bits:integer_bytes(Expected, 8, big, Bytes),
- bson_bits:integer_bytes(Got, 8, big, Bytes).
-
-test('64-bit big-endian, zero', [true(Got == Expected)]) :-
- Expected = 0,
- bson_bits:integer_bytes(Expected, 8, big, Bytes),
- bson_bits:integer_bytes(Got, 8, big, Bytes).
-
-test('64-bit big-endian, -1', [true(Got == Expected)]) :-
- Expected = -1,
- bson_bits:integer_bytes(Expected, 8, big, Bytes),
- bson_bits:integer_bytes(Got, 8, big, Bytes).
-
-test('64-bit big-endian, 1', [true(Got == Expected)]) :-
- Expected = 1,
- bson_bits:integer_bytes(Expected, 8, big, Bytes),
- bson_bits:integer_bytes(Got, 8, big, Bytes).
-
-test('64-bit big-endian, verify endian', [true(Got == Expected)]) :-
- Expected = [0,0,0,0,0,0,0,1],
- bson_bits:integer_bytes(1, 8, big, Got).
-
-test('64-bit big-endian, min', [true(Got == Expected)]) :-
- Expected is -2**63,
- bson_bits:integer_bytes(Expected, 8, big, Bytes),
- bson_bits:integer_bytes(Got, 8, big, Bytes).
-
-test('64-bit big-endian, min-1', [true(Got \== Expected)]) :-
- Expected is -2**63 - 1, % Too low.
- bson_bits:integer_bytes(Expected, 8, big, Bytes),
- bson_bits:integer_bytes(Got, 8, big, Bytes).
-
-test('64-bit big-endian, max', [true(Got == Expected)]) :-
- Expected is 2**63 - 1,
- bson_bits:integer_bytes(Expected, 8, big, Bytes),
- bson_bits:integer_bytes(Got, 8, big, Bytes).
-
-test('64-bit big-endian, max+1', [true(Got \== Expected)]) :-
- Expected is 2**63, % Too high.
- bson_bits:integer_bytes(Expected, 8, big, Bytes),
- bson_bits:integer_bytes(Got, 8, big, Bytes).
-
-% ------------------------------------
-
-test('64-bit little-endian, zero', [true(Got == Expected)]) :-
- Expected = 0,
- bson_bits:integer_bytes(Expected, 8, little, Bytes),
- bson_bits:integer_bytes(Got, 8, little, Bytes).
-
-test('64-bit little-endian, -1', [true(Got == Expected)]) :-
- Expected = -1,
- bson_bits:integer_bytes(Expected, 8, little, Bytes),
- bson_bits:integer_bytes(Got, 8, little, Bytes).
-
-test('64-bit little-endian, 1', [true(Got == Expected)]) :-
- Expected = 1,
- bson_bits:integer_bytes(Expected, 8, little, Bytes),
- bson_bits:integer_bytes(Got, 8, little, Bytes).
-
-test('64-bit little-endian, verify endian', [true(Got == Expected)]) :-
- Expected = [1,0,0,0,0,0,0,0],
- bson_bits:integer_bytes(1, 8, little, Got).
-
-test('64-bit little-endian, min', [true(Got == Expected)]) :-
- Expected is -2**63,
- bson_bits:integer_bytes(Expected, 8, little, Bytes),
- bson_bits:integer_bytes(Got, 8, little, Bytes).
-
-test('64-bit little-endian, min-1', [true(Got \== Expected)]) :-
- Expected is -2**63 - 1, % Too low.
- bson_bits:integer_bytes(Expected, 8, little, Bytes),
- bson_bits:integer_bytes(Got, 8, little, Bytes).
-
-test('64-bit little-endian, max', [true(Got == Expected)]) :-
- Expected is 2**63 - 1,
- bson_bits:integer_bytes(Expected, 8, little, Bytes),
- bson_bits:integer_bytes(Got, 8, little, Bytes).
-
-test('64-bit little-endian, max+1', [true(Got \== Expected)]) :-
- Expected is 2**63, % Too high.
- bson_bits:integer_bytes(Expected, 8, little, Bytes),
- bson_bits:integer_bytes(Got, 8, little, Bytes).
-
-:- end_tests('bson_bits:integer_bytes/4').
-
-:- begin_tests('bson_bits:hex_bytes/2').
-
-test('hex to bytes, bad input should throw', [throws(_)]) :-
- Expected = bad(input),
- bson_bits:hex_bytes(Expected, _Bytes).
-
-test('hex <-> bytes', [true(Got == Expected)]) :-
- Expected = '47cc67093475061e3d95369d',
- bson_bits:hex_bytes(Expected, Bytes),
- bson_bits:hex_bytes(Got, Bytes).
-
-test('hex to bytes, verify big endian', [true(Got == Expected)]) :-
- Hex = '47cc6709',
- Expected = [0x47,0xcc,0x67,0x09],
- bson_bits:hex_bytes(Hex, Got).
-
-test('hex to bytes, odd length should fail', [fail]) :-
- HexOddLength = '47c',
- bson_bits:hex_bytes(HexOddLength, _Bytes).
-
-test('bytes to hex, low byte is zero-padded', [true(Got == Expected)]) :-
- Bytes = [0x0f],
- Expected = '0f',
- bson_bits:hex_bytes(Got, Bytes).
-
-:- end_tests('bson_bits:hex_bytes/2').
View
204 src/bson/bson_decoder.pl
@@ -1,204 +0,0 @@
-/** <module> BSON decoder.
- *
- * This module is private. See bson.
- */
-
-:- module(_,
- [
- bytes_to_doc/2,
- bytes_to_docs/2
- ]).
-
-:- include(misc(common)).
-
-%% bytes_to_doc(+Bytes, ?Doc) is semidet.
-%
-% True if Bytes is the BSON byte-encoding of Doc.
-%
-% @throws bson_error(Reason)
-
-bytes_to_doc(Bytes, Doc) :-
- bytes_to_docs(Bytes, [Doc]).
-
-%% bytes_to_docs(+Bytes, ?Docs) is semidet.
-%
-% True if Bytes is the flat-list BSON byte-encoding of all the
-% documents in the list Docs.
-%
-% @throws bson_error(Reason)
-
-bytes_to_docs([], []) :- !.
-bytes_to_docs(Bytes, [Doc|Docs]) :-
- phrase(document(Doc), Bytes, RestBytes),
- !,
- bytes_to_docs(RestBytes, Docs).
-bytes_to_docs(_Bytes, _Docs) :-
- throw(bson_error(invalid)).
-
-% Note: This predicate does no validation on the length of the document
-% being parsed. The document is either valid and therefore successfully
-% parsed, or the parse fails. We trust the database server to send us valid
-% documents and therefore we ignore the length.
-document(Elements) -->
- int32(_LengthEntireDocIgnored),
- elements(Elements),
- [0].
-
-elements([]) --> [].
-elements([Key-Value|Elements]) -->
- element(Key, Value),
- elements(Elements).
-
-element(Key, Value) -->
- [Tag],
- key(Key),
- value(Tag, Value).
-
-key(Name) -->
- c_string(Name).
-
-value(0x01, Value) --> value_double(Value).
-value(0x02, Value) --> value_string(Value).
-value(0x03, Value) --> value_document(Value).
-value(0x04, Value) --> value_array(Value).
-value(0x05, Value) --> value_binary(Value).
-value(0x06, Value) --> value_undefined(Value). % Deprecated.
-value(0x07, Value) --> value_object_id(Value).
-value(0x08, Value) --> value_boolean(Value).
-value(0x09, Value) --> value_utc(Value).
-value(0x0a, Value) --> value_null(Value).
-value(0x0b, Value) --> value_regex(Value).
-value(0x0c, Value) --> value_db_pointer(Value). % Deprecated.
-value(0x0d, Value) --> value_js(Value).
-value(0x0e, Value) --> value_symbol(Value). % Deprecated
-value(0x0f, Value) --> value_js_with_scope(Value).
-value(0x10, Value) --> value_int32(Value).
-value(0x11, Value) --> value_mongostamp(Value).
-value(0x12, Value) --> value_int64(Value).
-value(0xff, Value) --> value_min(Value).
-value(0x7f, Value) --> value_max(Value).
-
-value_array(Values) -->
- document(Document),
- { pairs_keys_values(Document, _Keys, Values) }.
-
-value_document(Document) -->
- document(Document).
-
-value_string(Text) -->
- string(Text).
-
-value_regex(regex(Pattern,Options)) -->
- c_string(Pattern),
- c_string(Options).
-
-value_db_pointer(db_pointer(Text,ObjectId)) -->
- string(Text),
- object_id(ObjectId).
-
-value_utc(utc(Timestamp)) -->
- int64(Timestamp).
-
-value_mongostamp(mongostamp(Mongostamp)) -->
- int64(Mongostamp).
-
-value_null(+null) --> [].
-
-value_min(+min) --> [].
-
-value_max(+max) --> [].
-
-value_undefined(+undefined) --> [].
-
-value_boolean(+false) --> [0], !.
-value_boolean(+true) --> [1], !.
-value_boolean(_) --> { throw(bson_error(invalid_boolean)) }.
-
-value_binary(binary(Subtype,Bytes)) -->
- int32(Length),
- subtype(Subtype),
- bytes_n(Bytes, Length).
-
-value_js(js(JsCode)) -->
- string(JsCode).
-
-% Note: See document//1 on why we ignore the length.
-value_js_with_scope(js(JsCode,MappingsDoc)) -->
- int32(_LengthEntireJsWithScopeIgnored),
- string(JsCode),
- document(MappingsDoc).
-
-value_symbol(symbol(Symbol)) -->
- string(Symbol).
-
-value_object_id(object_id(ObjectId)) -->
- object_id(ObjectId).
-
-value_double(Double) -->
- double(Double).
-
-value_int32(Integer) -->
- int32(Integer).
-
-value_int64(Integer) -->
- int64(Integer).
-
-pairs_keys_values([], [], []).
-pairs_keys_values([Key-Value|Pairs], [Key|Keys], [Value|Values]) :-
- pairs_keys_values(Pairs, Keys, Values).
-
-object_id(ObjectId) -->
- bytes_n(Bytes, 12),
- { bson_bits:hex_bytes(ObjectId, Bytes) }.
-
-subtype(generic) --> [0x00], !.
-subtype(function) --> [0x01], !.
-subtype(old_generic) --> [0x02], !. % Deprecated.
-subtype(uuid_old) --> [0x03], !. % Deprecated.
-subtype(uuid) --> [0x04], !.
-subtype(md5) --> [0x05], !.
-subtype(user_defined) --> [0x80], !.
-subtype(Unknown) -->
- { throw(bson_error('unknown subtype', [Unknown])) }.
-
-string(Atom) -->
- int32(Length),
- string(Atom, Length).
-
-c_string(Atom) -->
- bytes_stop_on_nul(Bytes),
- { bson_unicode:utf8_bytes(Atom, Bytes) }.
-
-string(Atom, Length) -->
- n_bytes_including_nul(Bytes, Length),
- { bson_unicode:utf8_bytes(Atom, Bytes) }.
-
-bytes_stop_on_nul([]) --> [0], !.
-bytes_stop_on_nul([NotNul|Bytes]) -->
- [NotNul],
- bytes_stop_on_nul(Bytes).
-
-n_bytes_including_nul(Bytes, Length) -->
- { LengthMinusNul is Length - 1 },
- bytes_n(Bytes, LengthMinusNul),
- [0].
-
-bytes_n([], 0) --> [], !.
-bytes_n([Byte|Bytes], Length0) -->
- [Byte], % May be anything.
- { Length1 is Length0 - 1 },
- bytes_n(Bytes, Length1).
-
-int32(Integer) -->
- int_size(Integer, 4).
-
-int64(Integer) -->
- int_size(Integer, 8).
-
-int_size(Integer, N) -->
- bytes_n(Bytes, N),
- { bson_bits:integer_bytes(Integer, N, little, Bytes) }.
-
-double(Double) -->
- bytes_n(Bytes, 8),
- { bson_bits:float_bytes(Double, Bytes) }.
View
596 src/bson/bson_decoder.plt
@@ -1,596 +0,0 @@
-:- include(misc(common)).
-
-% Note: The first four bytes in a document represent an integer
-% that dictates the total byte length of the document. This is currently
-% ignored by the decoder, so many of these tests simply mark them as
-% "doc,length,not,implemented". This is partly due to the fact that
-% they are being ignored and partly due to laziness.
-
-:- begin_tests('bson_decoder:bytes_to_docs/2').
-
-test('no docs', [true(Got == Expected)]) :-
- Bytes = [],
- Expected = [],
- bson_decoder:bytes_to_docs(Bytes, Got).
-
-test('several empty docs', [true(Got == Expected)]) :-
- Bytes =
- [
- 5,0,0,0, 0,
- 5,0,0,0, 0
- ],
- Expected =
- [
- [],
- []
- ],
- bson_decoder:bytes_to_docs(Bytes, Got).
-
-test('several more complex docs', [true(Got == Expected)]) :-
- Bytes =
- [
- % Doc 1.
- 17,0,0,0, % Length of top doc.
- 0x03, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 5,0,0,0, % Length of embedded doc.
- 0, % End of embedded doc.
- 0, % End of top doc.
- % Doc 2.
- 17,0,0,0, % Length of top doc.
- 0x03, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 5,0,0,0, % Length of embedded doc.
- 0, % End of embedded doc.
- 0 % End of top doc.
- ],
- Expected =
- [
- [hello - []],
- [hello - []]
- ],
- bson_decoder:bytes_to_docs(Bytes, Got).
-
-:- end_tests('bson_decoder:bytes_to_docs/2').
-
-:- begin_tests('bson_decoder:bytes_to_doc/2').
-
-test('empty doc', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0 % End of top doc.
- ],
- Expected =
- [
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x01, float', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x01, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 51,51,51,51, 51,51,20,64, % Double data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - 5.05
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x02, string', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x02, % Tag.
- 0xc3,0xa4, 0, % Ename.
- 6,0,0,0, % String's byte length, incl. nul.
- 0xc3,0xa4, 0, 0xc3,0xa4, 0, % String data.
- 0 % End of top doc.
- ],
- Expected =
- [
- 'ä' - \0ä'
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x02, nuls not allowed in ename', [throws(bson_error(_))]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x02, % Tag.
- 0xc3,0xa4, 0, 0xc3,0xa4, 0, % Ename, INVALID.
- 3,0,0,0, % String's byte length, incl. nul.
- 0xc3,0xa4, 0, % String data.
- 0 % End of top doc.
- ],
- bson_decoder:bytes_to_doc(Bytes, _Got).
-
-test('0x03, embedded doc', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x03, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 38,0,0,0, % Length of embedded doc.
- 0x02, % Tag.
- 97, 0, % Ename.
- 8,0,0,0, % String's byte length, incl. nul.
- 97,119,101,115,111,109,101, 0, % String data.
- 0x01, % Tag.
- 98, 0, % Ename.
- 51,51,51,51,51,51,20,64, % Double 8-byte data.
- 0x10, % Tag.
- 99, 0, % Ename.
- 194,7,0,0, % Int32 data.
- 0, % End of embedded doc.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello -
- [
- 'a' - 'awesome',
- 'b' - 5.05,
- 'c' - 1986
- ]
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x03, embedded empty doc', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x03, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 5,0,0,0, % Length of embedded doc.
- 0, % End of embedded doc.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - []
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x04, embedded array', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x04, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 38,0,0,0, % Length of embedded doc.
- 0x02, % Tag.
- 48, 0, % Ename, index 0.
- 8,0,0,0, % String's byte length, incl. nul.
- 97,119,101,115,111,109,101, 0, % String data.
- 0x01, % Tag.
- 49, 0, % Ename, index 1.
- 51,51,51,51,51,51,20,64, % Double 8-byte data.
- 0x10, % Tag.
- 50, 0, % Ename, index 2.
- 194,7,0,0, % Int32 data.
- 0, % End of embedded doc.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - ['awesome', 5.05, 1986]
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x04, embedded empty array', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x04, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 5,0,0,0, % Length of embedded doc.
- 0, % End of embedded doc.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - []
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x05, binary, generic', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x05, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 5,0,0,0, % Length of binary data.
- 0x00, % Subtype.
- 0,1,2,1,0, % Binary data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - binary(generic, [0,1,2,1,0])
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x05, binary, function', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x05, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 5,0,0,0, % Length of binary data.
- 0x01, % Subtype.
- 0,1,2,1,0, % Binary data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - binary(function, [0,1,2,1,0])
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x05, binary, old generic', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x05, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 5,0,0,0, % Length of binary data.
- 0x02, % Subtype.
- 0,1,2,1,0, % Binary data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - binary(old_generic, [0,1,2,1,0])
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x05, binary, uuid_old', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x05, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 5,0,0,0, % Length of binary data.
- 0x03, % Subtype.
- 0,1,2,1,0, % Binary data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - binary(uuid_old, [0,1,2,1,0])
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x05, binary, uuid', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x05, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 5,0,0,0, % Length of binary data.
- 0x04, % Subtype.
- 0,1,2,1,0, % Binary data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - binary(uuid, [0,1,2,1,0])
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x05, binary, md5', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x05, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 5,0,0,0, % Length of binary data.
- 0x05, % Subtype.
- 0,1,2,1,0, % Binary data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - binary(md5, [0,1,2,1,0])
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x05, binary, user defined', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x05, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 5,0,0,0, % Length of binary data.
- 0x80, % Subtype.
- 0,1,2,1,0, % Binary data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - binary(user_defined, [0,1,2,1,0])
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x06, undefined', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x06, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - +undefined
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x07, object id', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x07, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 0x47,0xcc,0x67,0x09, % ObjectID, time.
- 0x34,0x75,0x06, % ObjectID, machine.
- 0x1e,0x3d, % ObjectID, pid.
- 0x95,0x36,0x9d, % ObjectID, inc.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - object_id('47cc67093475061e3d95369d')
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x08, boolean true', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x08, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 1, % Boolean data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - +true
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x08, boolean false', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x08, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 0, % Boolean data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - +false
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x08, boolean invalid', [throws(bson_error(invalid_boolean))]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x08, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 2, % Boolean data, INVALID value.
- 0 % End of top doc.
- ],
- bson_decoder:bytes_to_doc(Bytes, _Got).
-
-test('0x09, utc datetime', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x09, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 188,11,99,58,47,1,0,0, % UTC datetime data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - utc(1302354660284) % date(2011, 4, 9, ...)
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x0a, null', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x0a, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - +null
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x0b, regex', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x0b, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 97, 0, % Regex pattern.
- 105, 0, % Regex options.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - regex('a','i')
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x0c, db pointer', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x0c, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 2,0,0,0, % String's byte length, incl. nul.
- 97, 0, % String data.
- 0x47,0xcc,0x67,0x09, % ObjectID, time.
- 0x34,0x75,0x06, % ObjectID, machine.
- 0x1e,0x3d, % ObjectID, pid.
- 0x95,0x36,0x9d, % ObjectID, inc.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - db_pointer('a', '47cc67093475061e3d95369d')
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x0d, js', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x0d, % Tag.
- 106,115, 0, % Ename.
- 9,0,0,0, % String's byte length, incl. nul.
- 99,111,100,101,32,46,46,46, 0, % String data.
- 0 % End of top doc.
- ],
- Expected =
- [
- js - js('code ...')
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x0e, symbol', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x0e, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 5,0,0,0, % String's byte length, incl. nul.
- 97,116,111,109, 0, % String data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - symbol(atom)
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x0f, js with scope', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x0f, % Tag.
- 106,115, 0, % Ename.
- doc,length,not,implemented, % Length of entire JS with scope.
- 9,0,0,0, % String's byte length, incl. nul.
- 99,111,100,101,32,46,46,46, 0, % String data.
- doc,length,not,implemented, % Length of embedded doc.
- 0x10, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 32,0,0,0, % Int32 data.
- 0, % End of embedded doc.
- 0 % End of top doc.
- ],
- Expected =
- [
- js - js('code ...', ['hello'-32])
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x10, int32', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x10, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 32,0,0,0, % Int32 data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - 32
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x11, mongostamp', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x11, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 0,0,0,0, 0,0,0,0, % Int64 mongostamp data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - mongostamp(0)
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x12, int64', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x12, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 32,0,0,0, 0,0,0,0, % Int64 data.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - 32
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0xff, min', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0xff, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - +min
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('0x7f, max', [true(Got == Expected)]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x7f, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 0 % End of top doc.
- ],
- Expected =
- [
- hello - +max
- ],
- bson_decoder:bytes_to_doc(Bytes, Got).
-
-test('invalid bson, missing terminating nul', [throws(bson_error(invalid))]) :-
- Bytes =
- [
- doc,length,not,implemented, % Length of top doc.
- 0x10, % Tag.
- 104,101,108,108,111, 0, % Ename.
- 32,0,0,0 % Int32 data.
- % Missing nul at end-of-doc.
- ],
- bson_decoder:bytes_to_doc(Bytes, _Got).
-
-:- end_tests('bson_decoder:bytes_to_doc/2').
View
104 src/bson/bson_doc.pl
@@ -1,104 +0,0 @@
-/** <module> BSON document manipulation.
- *
- * Most of these predicates run in O(n), but that may change.
- */
-
-:- module(_,
- [
- doc_is_valid/1,
- doc_empty/1,
- doc_get/3,
- doc_get_strict/3,
- doc_put/4,
- doc_delete/3,
- doc_keys/2,
- doc_values/2,
- doc_keys_values/3
- ]).
-
-:- include(misc(common)).
-
-%% doc_is_valid(+Doc) is semidet.
-%
-% True if Doc is a valid BSON document.
-%
-% Note: Right now, this is accomplished by converting it to bytes
-% and failing if an exception is thrown. This can probably be done
-% more efficiently.
-
-doc_is_valid(Doc) :-
- catch(
- bson:doc_bytes(Doc, _Bytes),
- bson_error(_),
- fail).
-
-%% doc_empty(?Doc) is semidet.
-%
-% True if Doc is an empty BSON document.
-
-doc_empty([]).
-
-%% doc_get(+Doc, +Key, ?Value) is semidet.
-%
-% True if Value is the value associated with Key in Doc
-% or +null if Key cannot be found. This means that there
-% is no way of knowing if Value actually was +null or not found.
-
-doc_get([], _, +null).
-doc_get([K-V|_], K, V) :- !.
-doc_get([_|Pairs], K, V) :-
- doc_get(Pairs, K, V).
-
-%% doc_get_strict(+Doc, +Key, ?Value) is semidet.
-%
-% True if Value is the value associated with Key in Doc,
-% or fails if Key is not found or does not match Value.
-
-doc_get_strict([K-V|_], K, V) :- !.
-doc_get_strict([_|Pairs], K, V) :-
- doc_get_strict(Pairs, K, V).
-
-%% doc_put(+Doc, +Key, +Value, ?NewDoc) is semidet.
-%
-% True if NewDoc is Doc with the addition or update of the
-% association Key-Value.
-
-doc_put([], K, V, [K-V]).
-doc_put([K-_|Pairs], K, V, [K-V|Pairs]) :- !.
-doc_put([Other|Pairs], K, V, [Other|Pairs1]) :-
- doc_put(Pairs, K, V, Pairs1).
-
-%% doc_delete(+Doc, +Key, ?NewDoc) is semidet.
-%
-% True if NewDoc is Doc with the association removed that has
-% Key as key. At most one association is removed. No change if
-% Key is not found.
-
-doc_delete([], _, []).
-doc_delete([K-_|Pairs], K, Pairs) :- !.
-doc_delete([Other|Pairs], K, [Other|Pairs1]) :-
- doc_delete(Pairs, K, Pairs1).
-
-%% doc_keys(+Doc, ?Keys) is semidet.
-%
-% True if Keys is the keys for the associations in Doc.
-
-doc_keys(Doc, Keys) :-
- doc_keys_values(Doc, Keys, _Values).
-
-%% doc_values(+Doc, ?Values) is semidet.
-%
-% True if Values is the values for the associations in Doc.
-
-doc_values(Doc, Values) :-
- doc_keys_values(Doc, _Keys, Values).
-
-%% doc_keys_values(+Doc, ?Keys, ?Values) is semidet.
-%% doc_keys_values(?Doc, +Keys, +Values) is semidet.
-%
-% True if Doc is the list of successive associations of
-% Keys and Values.
-
-doc_keys_values([], [], []).
-doc_keys_values([K-V|Pairs], [K|Keys], [V|Values]) :-
- doc_keys_values(Pairs, Keys, Values).
View
174 src/bson/bson_doc.plt
@@ -1,174 +0,0 @@
-:- include(misc(common)).
-
-:- begin_tests('bson_doc:doc_is_valid/1').
-
-test('valid') :-
- Doc =
- [
- a - +null
- ],
- bson_doc:doc_is_valid(Doc).
-
-test('invalid', [fail]) :-
- Doc =
- [
- a - +nul % Unknown constant.
- ],
- bson_doc:doc_is_valid(Doc).
-
-:- end_tests('bson_doc:doc_is_valid/1').
-
-:- begin_tests('bson_doc:doc_empty/1').
-
-test('empty') :-
- bson_doc:doc_empty(Doc),
- bson_doc:doc_empty(Doc).
-
-test('non-empty', [fail]) :-
- bson_doc:doc_empty(Doc),
- bson_doc:doc_put(Doc, key, value, Doc1),
- bson_doc:doc_empty(Doc1).
-
-test('fill and empty') :-
- bson_doc:doc_empty(Doc),
- bson_doc:doc_put(Doc, key, value, Doc1),
- bson_doc:doc_delete(Doc1, key, Doc2),
- bson_doc:doc_empty(Doc2).
-
-:- end_tests('bson_doc:doc_empty/1').
-
-:- begin_tests('bson_doc:doc_get/3').
-
-test('not found') :-
- Doc =
- [
- key - value
- ],
- bson_doc:doc_get(Doc, notfoundkey, +null).
-
-test('not found in empty doc') :-
- Doc = [],
- bson_doc:doc_get(Doc, notfoundkey, +null).
-
-test('found') :-
- Doc =
- [
- key - value
- ],
- bson_doc:doc_get(Doc, key, value).
-
-test('found null') :-
- Doc =
- [
- key - +null
- ],
- bson_doc:doc_get(Doc, key, +null).
-
-:- end_tests('bson_doc:doc_get/3').
-
-:- begin_tests('bson_doc:doc_get_strict/3').
-
-test('not found') :-
- Doc =
- [
- key - value
- ],
- \+ bson_doc:doc_get_strict(Doc, notfoundkey, _).
-
-test('found') :-
- Doc =
- [
- key - value
- ],
- bson_doc:doc_get_strict(Doc, key, value).
-
-test('found null') :-
- Doc =
- [
- key - +null
- ],
- bson_doc:doc_get_strict(Doc, key, +null).
-
-:- end_tests('bson_doc:doc_get_strict/3').
-
-:- begin_tests('bson_doc:doc_put/4').
-
-test('put in empty') :-
- Doc = [],
- bson_doc:doc_get(Doc, key, +null),
- bson_doc:doc_put(Doc, key, value, Doc1),
- bson_doc:doc_get(Doc1, key, value).
-
-test('put in non-empty') :-
- Doc =
- [
- keyold - valueold
- ],
- bson_doc:doc_get(Doc, keyold, valueold),
- bson_doc:doc_get(Doc, keynew, +null),
- bson_doc:doc_put(Doc, keynew, valuenew, Doc1),
- bson_doc:doc_get(Doc1, keyold, valueold),
- bson_doc:doc_get(Doc1, keynew, +null).
-
-:- end_tests('bson_doc:doc_put/4').
-
-:- begin_tests('bson_doc:doc_delete/3').
-
-test('delete from empty') :-
- Doc = [],
- bson_doc:doc_delete(Doc, notfoundkey, Doc).
-
-test('delete not found') :-
- Doc =
- [
- key - value
- ],
- bson_doc:doc_delete(Doc, notfoundkey, Doc).
-
-test('delete only key') :-
- Doc =
- [
- key - value
- ],
- bson_doc:doc_delete(Doc, key, Doc1),
- bson_doc:doc_get(Doc1, key, +null).
-
-test('delete one key') :-
- Doc =
- [
- key1 - value1,
- key2 - value2
- ],
- bson_doc:doc_delete(Doc, key2, Doc1),
- bson_doc:doc_get(Doc1, key1, value1),
- bson_doc:doc_get(Doc1, key2, +null).
-
-:- end_tests('bson_doc:doc_delete/3').
-
-:- begin_tests('bson_doc:doc_keys/2').
-
-test('doc_keys 1', [true(Got == Expected)]) :-
- Doc =
- [
- a - 1,
- b - 2,
- c - 3
- ],
- Expected = [a,b,c],
- bson_doc:doc_keys(Doc, Got).
-
-:- end_tests('bson_doc:doc_keys/2').
-
-:- begin_tests('bson_doc:doc_values/2').
-
-test('doc_values 1', [true(Got == Expected)]) :-