forked from selectel/bson-haskell
-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathSize.hs
71 lines (60 loc) · 2.21 KB
/
Size.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
{-# LANGUAGE MagicHash #-}
module Data.Bson.Size (sizeOfDocument) where
import Data.Bson
import qualified Data.ByteString as BS
import Data.Text (Text)
import Data.Text.Unsafe (lengthWord8)
import GHC.Num.Integer (integerSizeInBase#)
import GHC.Word (Word (..))
-- | Size in bytes of the BSON document when serialized to binary format.
sizeOfDocument :: Document -> Int
sizeOfDocument doc = sum (map sizeOfField doc) + 5
-- Additional 5 bytes = 4 bytes (size) + 1 byte (null terminator)
sizeOfField :: Field -> Int
sizeOfField (k := v) = sizeOfLabel k + sizeOfValue v + 1
-- Additional 1 byte = element type
sizeOfLabel :: Text -> Int
sizeOfLabel = sizeOfCString
sizeOfValue :: Value -> Int
sizeOfValue v = case v of
Float _ -> 8 -- 64-bit binary floating point
String x -> sizeOfString x
Doc x -> sizeOfDocument x
Array x -> sizeOfArray x
Bin (Binary x) -> sizeOfBinary x
Fun (Function x) -> sizeOfBinary x
Uuid (UUID x) -> sizeOfBinary x
Md5 (MD5 x) -> sizeOfBinary x
UserDef (UserDefined x) -> sizeOfBinary x
ObjId _ -> 12
Bool _ -> 1
UTC _ -> 8
Null -> 0
RegEx (Regex pattern opts) -> sizeOfCString pattern + sizeOfCString opts
JavaScr (Javascript [] code) -> sizeOfString code
JavaScr (Javascript env code) -> sizeOfClosure env code -- "code with scope"
Sym (Symbol x) -> sizeOfString x
Int32 _ -> 4
Int64 _ -> 8
Stamp _ -> 8
MinMax _ -> 0
sizeOfCString :: Text -> Int
sizeOfCString t = lengthWord8 t + 1
-- Additional 1 byte = null terminator
sizeOfString :: Text -> Int
sizeOfString t = sizeOfCString t + 4
-- Additional 4 bytes = size of string
sizeOfClosure :: Document -> Text -> Int
sizeOfClosure env code = 4 + sizeOfDocument env + sizeOfString code
sizeOfBinary :: BS.ByteString -> Int
sizeOfBinary x = 5 + BS.length x
-- Additional 5 bytes = 4 bytes (size) + 1 byte (subtype)
sizeOfArray :: [Value] -> Int
sizeOfArray vs = 5 + sum (zipWith go [0..] vs)
-- Additional 5 bytes = 4 bytes (size) + 1 byte (null terminator)
where
go i v = 2 + intLen i + sizeOfValue v
-- Additional 2 bytes = 1 byte (element type) + 1 byte (null terminator of key name)
-- Length of the string representing the integer in base 10
intLen 0 = 1
intLen i = fromIntegral $ W# (integerSizeInBase# 10## i)