啊鑫
7 天以前 fca192d3c38c5dcfbb6ace8bc71d6078f6a079b2
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
    MIT License http://www.opensource.org/licenses/mit-license.php
*/
 
"use strict";
 
/** @typedef {import("./ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("./ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
 
/** @typedef {EXPECTED_FUNCTION} CacheAssoc */
 
/**
 * @template T
 * @typedef {WeakMap<CacheAssoc, ObjectStructure<T>>}
 */
const cache = new WeakMap();
 
/**
 * @template T
 */
class ObjectStructure {
    constructor() {
        this.keys = undefined;
        this.children = undefined;
    }
 
    /**
     * @param {keyof T[]} keys keys
     * @returns {keyof T[]} keys
     */
    getKeys(keys) {
        if (this.keys === undefined) this.keys = keys;
        return this.keys;
    }
 
    /**
     * @param {keyof T} key key
     * @returns {ObjectStructure<T>} object structure
     */
    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;
    }
}
 
/**
 * @template T
 * @param {(keyof T)[]} keys keys
 * @param {CacheAssoc} cacheAssoc cache assoc fn
 * @returns {(keyof T)[]} keys
 */
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 {
    /**
     * @template {object} T
     * @param {T} obj plain object
     * @param {ObjectSerializerContext} context context
     */
    serialize(obj, context) {
        const keys = /** @type {(keyof T)[]} */ (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);
        }
    }
 
    /**
     * @template {object} T
     * @param {ObjectDeserializerContext} context context
     * @returns {T} plain object
     */
    deserialize(context) {
        const keys = context.read();
        const obj = /** @type {T} */ ({});
        if (Array.isArray(keys)) {
            for (const key of keys) {
                obj[/** @type {keyof T} */ (key)] = context.read();
            }
        } else if (keys !== null) {
            obj[/** @type {keyof T} */ (keys)] = context.read();
        }
        return obj;
    }
}
 
module.exports = PlainObjectSerializer;