马宇豪
2024-07-16 f591c27b57e2418c9495bc02ae8cfff84d35bc18
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*
    MIT License http://www.opensource.org/licenses/mit-license.php
*/
 
"use strict";
 
/** @typedef {import("./ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("./ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
 
const cache = new WeakMap();
 
class ObjectStructure {
    constructor() {
        this.keys = undefined;
        this.children = undefined;
    }
 
    getKeys(keys) {
        if (this.keys === undefined) this.keys = keys;
        return this.keys;
    }
 
    key(key) {
        if (this.children === undefined) this.children = new Map();
        const child = this.children.get(key);
        if (child !== undefined) return child;
        const newChild = new ObjectStructure();
        this.children.set(key, newChild);
        return newChild;
    }
}
 
const getCachedKeys = (keys, cacheAssoc) => {
    let root = cache.get(cacheAssoc);
    if (root === undefined) {
        root = new ObjectStructure();
        cache.set(cacheAssoc, root);
    }
    let current = root;
    for (const key of keys) {
        current = current.key(key);
    }
    return current.getKeys(keys);
};
 
class PlainObjectSerializer {
    /**
     * @param {Object} obj plain object
     * @param {ObjectSerializerContext} context context
     */
    serialize(obj, context) {
        const keys = Object.keys(obj);
        if (keys.length > 128) {
            // Objects with so many keys are unlikely to share structure
            // with other objects
            context.write(keys);
            for (const key of keys) {
                context.write(obj[key]);
            }
        } else if (keys.length > 1) {
            context.write(getCachedKeys(keys, context.write));
            for (const key of keys) {
                context.write(obj[key]);
            }
        } else if (keys.length === 1) {
            const key = keys[0];
            context.write(key);
            context.write(obj[key]);
        } else {
            context.write(null);
        }
    }
    /**
     * @param {ObjectDeserializerContext} context context
     * @returns {Object} plain object
     */
    deserialize(context) {
        const keys = context.read();
        const obj = {};
        if (Array.isArray(keys)) {
            for (const key of keys) {
                obj[key] = context.read();
            }
        } else if (keys !== null) {
            obj[keys] = context.read();
        }
        return obj;
    }
}
 
module.exports = PlainObjectSerializer;