All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.wjybxx.dson.DsonReaderUtils Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
/*
 * Copyright 2023-2024 wjybxx([email protected])
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.wjybxx.dson;

import cn.wjybxx.dson.internal.CodedUtils;
import cn.wjybxx.dson.internal.DsonInternals;
import cn.wjybxx.dson.io.DsonChunk;
import cn.wjybxx.dson.io.DsonIOException;
import cn.wjybxx.dson.io.DsonInput;
import cn.wjybxx.dson.io.DsonOutput;
import cn.wjybxx.dson.types.*;

import java.util.List;

/**
 * @author wjybxx
 * date - 2023/5/31
 */
public class DsonReaderUtils {

    /** 支持读取为bytes和直接写入bytes的数据类型 -- 这些类型不可以存储额外数据在WireType上 */
    public static final List VALUE_BYTES_TYPES = List.of(DsonType.STRING,
            DsonType.BINARY, DsonType.ARRAY, DsonType.OBJECT, DsonType.HEADER);

    // region number

    /**
     * 1.浮点数的前16位固定写入,因此只统计后16位
     * 2.wireType表示后导0对应的字节数
     * 3.由于编码依赖了上层的wireType比特位,因此不能写在Output接口中
     */
    public static int wireTypeOfFloat(float value) {
        int rawBits = Float.floatToRawIntBits(value);
        if ((rawBits & 0xFF) != 0) {
            return 0;
        }
        if ((rawBits & 0xFF00) != 0) {
            return 1;
        }
        return 2;
    }

    /** 小端编码,从末尾非0开始写入 */
    public static void writeFloat(DsonOutput output, float value, int wireType) {
        if (wireType == 0) {
            output.writeFloat(value);
            return;
        }

        int rawBits = Float.floatToRawIntBits(value);
        for (int i = 0; i < wireType; i++) {
            rawBits = rawBits >>> 8;
        }
        for (int i = wireType; i < 4; i++) {
            output.writeRawByte((byte) rawBits);
            rawBits = rawBits >>> 8;
        }
    }

    public static float readFloat(DsonInput input, int wireType) {
        if (wireType == 0) {
            return input.readFloat();
        }

        int rawBits = 0;
        for (int i = wireType; i < 4; i++) {
            rawBits |= (input.readRawByte() & 0XFF) << (8 * i);
        }
        return Float.intBitsToFloat(rawBits);
    }

    /**
     * 浮点数的前16位固定写入,因此只统计后48位
     */
    public static int wireTypeOfDouble(double value) {
        long rawBits = Double.doubleToRawLongBits(value);
        for (int i = 0; i < 6; i++) {
            byte v = (byte) rawBits;
            if (v != 0) {
                return i;
            }
            rawBits = rawBits >>> 8;
        }
        return 6;
    }

    public static void writeDouble(DsonOutput output, double value, int wireType) {
        if (wireType == 0) {
            output.writeDouble(value);
            return;
        }

        long rawBits = Double.doubleToRawLongBits(value);
        for (int i = 0; i < wireType; i++) {
            rawBits = rawBits >>> 8;
        }
        for (int i = wireType; i < 8; i++) {
            output.writeRawByte((byte) rawBits);
            rawBits = rawBits >>> 8;
        }
    }

    public static double readDouble(DsonInput input, int wireType) {
        if (wireType == 0) {
            return input.readDouble();
        }

        long rawBits = 0;
        for (int i = wireType; i < 8; i++) {
            rawBits |= (input.readRawByte() & 0XFFL) << (8 * i);
        }
        return Double.longBitsToDouble(rawBits);
    }

    public static boolean readBool(DsonInput input, int wireTypeBits) {
        if (wireTypeBits == 1) {
            return true;
        }
        if (wireTypeBits == 0) {
            return false;
        }
        throw new DsonIOException("invalid wireType for bool, bits: " + wireTypeBits);
    }
    // endregion

    // region binary

    public static void writeBinary(DsonOutput output, Binary binary) {
        int sizeOfBinaryType = CodedUtils.computeRawVarInt32Size(binary.getType());
        output.writeFixed32(sizeOfBinaryType + binary.getData().length);
        output.writeUint32(binary.getType());
        output.writeRawBytes(binary.getData());
    }

    public static void writeBinary(DsonOutput output, int type, DsonChunk chunk) {
        int sizeOfBinaryType = CodedUtils.computeRawVarInt32Size(type);
        output.writeFixed32(sizeOfBinaryType + chunk.getLength());
        output.writeUint32(type);
        output.writeRawBytes(chunk.getBuffer(), chunk.getOffset(), chunk.getLength());
    }

    public static Binary readBinary(DsonInput input) {
        int size = input.readFixed32();
        int oldLimit = input.pushLimit(size);
        Binary binary;
        {
            int type = input.readUint32();
            int dataLength = input.getBytesUntilLimit();
            binary = new Binary(type, input.readRawBytes(dataLength));
        }
        input.popLimit(oldLimit);
        return binary;
    }

    // endregion

    // region 内置二元组
    public static void writeExtInt32(DsonOutput output, ExtInt32 extInt32, WireType wireType) {
        output.writeUint32(extInt32.getType());
        output.writeBool(extInt32.hasValue());
        if (extInt32.hasValue()) {
            wireType.writeInt32(output, extInt32.getValue());
        }
    }

    public static ExtInt32 readExtInt32(DsonInput input, WireType wireType) {
        int type = input.readUint32();
        boolean hasValue = input.readBool();
        int value = hasValue ? wireType.readInt32(input) : 0;
        return new ExtInt32(type, value, hasValue);
    }

    public static void writeExtInt64(DsonOutput output, ExtInt64 extInt64, WireType wireType) {
        output.writeUint32(extInt64.getType());
        output.writeBool(extInt64.hasValue());
        if (extInt64.hasValue()) {
            wireType.writeInt64(output, extInt64.getValue());
        }
    }

    public static ExtInt64 readExtInt64(DsonInput input, WireType wireType) {
        int type = input.readUint32();
        boolean hasValue = input.readBool();
        long value = hasValue ? wireType.readInt64(input) : 0;
        return new ExtInt64(type, value, hasValue);
    }

    public static void writeExtDouble(DsonOutput output, ExtDouble extDouble, int wireType) {
        output.writeUint32(extDouble.getType());
        output.writeBool(extDouble.hasValue());
        if (extDouble.hasValue()) {
            writeDouble(output, extDouble.getValue(), wireType);
        }
    }

    public static ExtDouble readExtDouble(DsonInput input, int wireType) {
        int type = input.readUint32();
        boolean hasValue = input.readBool();
        double value = hasValue ? readDouble(input, wireType) : 0;
        return new ExtDouble(type, value, hasValue);
    }

    public static int wireTypeOfExtString(ExtString extString) {
        int v = 0;
        if (extString.getType() != 0) {
            v |= ExtString.MASK_TYPE;
        }
        if (extString.hasValue()) {
            v |= ExtString.MASK_VALUE;
        }
        return v;
    }

    public static void writeExtString(DsonOutput output, ExtString extString) {
        if (extString.getType() != 0) {
            output.writeUint32(extString.getType());
        }
        if (extString.hasValue()) {
            output.writeString(extString.getValue());
        }
    }

    public static ExtString readExtString(DsonInput input, int wireTypeBits) {
        int type = DsonInternals.isEnabled(wireTypeBits, ExtString.MASK_TYPE) ? input.readUint32() : 0;
        String value = DsonInternals.isEnabled(wireTypeBits, ExtString.MASK_VALUE) ? input.readString() : null;
        return new ExtString(type, value);
    }
    // endregion

    // region 内置结构体
    public static int wireTypeOfRef(ObjectRef objectRef) {
        int v = 0;
        if (objectRef.hasNamespace()) {
            v |= ObjectRef.MASK_NAMESPACE;
        }
        if (objectRef.getType() != 0) {
            v |= ObjectRef.MASK_TYPE;
        }
        if (objectRef.getPolicy() != 0) {
            v |= ObjectRef.MASK_POLICY;
        }
        return v;
    }

    public static void writeRef(DsonOutput output, ObjectRef objectRef) {
        output.writeString(objectRef.getLocalId());
        if (objectRef.hasNamespace()) {
            output.writeString(objectRef.getNamespace());
        }
        if (objectRef.getType() != 0) {
            output.writeUint32(objectRef.getType());
        }
        if (objectRef.getPolicy() != 0) {
            output.writeUint32(objectRef.getPolicy());
        }
    }

    public static ObjectRef readRef(DsonInput input, int wireTypeBits) {
        String localId = input.readString();
        String namespace = DsonInternals.isEnabled(wireTypeBits, ObjectRef.MASK_NAMESPACE) ? input.readString() : null;
        int type = DsonInternals.isEnabled(wireTypeBits, ObjectRef.MASK_TYPE) ? input.readUint32() : 0;
        int policy = DsonInternals.isEnabled(wireTypeBits, ObjectRef.MASK_POLICY) ? input.readUint32() : 0;
        return new ObjectRef(localId, namespace, type, policy);
    }

    public static void writeTimestamp(DsonOutput output, OffsetTimestamp timestamp) {
        output.writeUint64(timestamp.getSeconds());
        output.writeUint32(timestamp.getNanos());
        output.writeSint32(timestamp.getOffset());
        output.writeUint32(timestamp.getEnables());
    }

    public static OffsetTimestamp readTimestamp(DsonInput input) {
        return new OffsetTimestamp(
                input.readUint64(),
                input.readUint32(),
                input.readSint32(),
                input.readUint32());
    }
    // endregion

    // region 特殊
    public static void writeValueBytes(DsonOutput output, DsonType type, byte[] data) {
        if (type == DsonType.STRING) {
            output.writeUint32(data.length);
        } else {
            output.writeFixed32(data.length);
        }
        output.writeRawBytes(data);
    }

    public static byte[] readValueAsBytes(DsonInput input, DsonType dsonType) {
        int size;
        if (dsonType == DsonType.STRING) {
            size = input.readUint32();
        } else {
            size = input.readFixed32();
        }
        return input.readRawBytes(size);
    }

    public static void checkReadValueAsBytes(DsonType dsonType) {
        if (!VALUE_BYTES_TYPES.contains(dsonType)) {
            throw DsonIOException.invalidDsonType(VALUE_BYTES_TYPES, dsonType);
        }
    }

    public static void checkWriteValueAsBytes(DsonType dsonType) {
        if (!VALUE_BYTES_TYPES.contains(dsonType)) {
            throw DsonIOException.invalidDsonType(VALUE_BYTES_TYPES, dsonType);
        }
    }

    public static void skipToEndOfObject(DsonInput input) {
        int size = input.getBytesUntilLimit();
        if (size > 0) {
            input.skipRawBytes(size);
        }
    }
    // endregion

    public static void skipValue(DsonInput input, DsonContextType contextType,
                                 DsonType dsonType, WireType wireType, int wireTypeBits) {
        int skip;
        switch (dsonType) {
            case FLOAT -> {
                skip = 4 - wireTypeBits;
            }
            case DOUBLE -> {
                skip = 8 - wireTypeBits;
            }
            case BOOLEAN, NULL -> {
                return;
            }
            case INT32 -> {
                wireType.readInt32(input);
                return;
            }
            case INT64 -> {
                wireType.readInt64(input);
                return;
            }
            case STRING -> {
                skip = input.readUint32();  // string长度
            }
            case EXT_INT32 -> {
                input.readUint32(); // 子类型
                if (input.readBool()) {
                    wireType.readInt32(input);
                }
                return;
            }
            case EXT_INT64 -> {
                input.readUint32(); // 子类型
                if (input.readBool()) {
                    wireType.readInt64(input);
                }
                return;
            }
            case EXT_DOUBLE -> {
                input.readUint32(); // 子类型
                skip = input.readBool() ? (8 - wireTypeBits) : 0;
                input.skipRawBytes(skip);
                return;
            }
            case EXT_STRING -> {
                if (DsonInternals.isEnabled(wireTypeBits, ExtString.MASK_TYPE)) {
                    input.readUint32(); // 子类型
                }
                if (DsonInternals.isEnabled(wireTypeBits, ExtString.MASK_VALUE)) {
                    skip = input.readUint32(); // string长度
                    input.skipRawBytes(skip);
                }
                return;
            }
            case REFERENCE -> {
                skip = input.readUint32(); // localId
                input.skipRawBytes(skip);

                if (DsonInternals.isEnabled(wireTypeBits, ObjectRef.MASK_NAMESPACE)) {
                    skip = input.readUint32(); // namespace
                    input.skipRawBytes(skip);
                }
                if (DsonInternals.isEnabled(wireTypeBits, ObjectRef.MASK_TYPE)) {
                    input.readUint32();
                }
                if (DsonInternals.isEnabled(wireTypeBits, ObjectRef.MASK_POLICY)) {
                    input.readUint32();
                }
                return;
            }
            case TIMESTAMP -> {
                input.readUint64();
                input.readUint32();
                input.readSint32();
                input.readUint32();
                return;
            }
            case BINARY, ARRAY, OBJECT, HEADER -> {
                skip = input.readFixed32();
            }
            default -> {
                throw DsonIOException.invalidDsonType(contextType, dsonType);
            }
        }
        if (skip > 0) {
            input.skipRawBytes(skip);
        }
    }

    public static DsonReaderGuide whatShouldIDo(DsonContextType contextType, DsonReaderState state) {
        if (contextType == DsonContextType.TOP_LEVEL) {
            if (state == DsonReaderState.END_OF_FILE) {
                return DsonReaderGuide.CLOSE;
            }
            if (state == DsonReaderState.VALUE) {
                return DsonReaderGuide.READ_VALUE;
            }
            return DsonReaderGuide.READ_TYPE;
        } else {
            return switch (state) {
                case TYPE -> DsonReaderGuide.READ_TYPE;
                case VALUE -> DsonReaderGuide.READ_VALUE;
                case NAME -> DsonReaderGuide.READ_NAME;
                case WAIT_START_OBJECT -> {
                    if (contextType == DsonContextType.HEADER) {
                        yield DsonReaderGuide.START_HEADER;
                    }
                    if (contextType == DsonContextType.ARRAY) {
                        yield DsonReaderGuide.START_ARRAY;
                    }
                    yield DsonReaderGuide.START_OBJECT;
                }
                case WAIT_END_OBJECT -> {
                    if (contextType == DsonContextType.HEADER) {
                        yield DsonReaderGuide.END_HEADER;
                    }
                    if (contextType == DsonContextType.ARRAY) {
                        yield DsonReaderGuide.END_ARRAY;
                    }
                    yield DsonReaderGuide.END_OBJECT;
                }
                case INITIAL, END_OF_FILE -> throw new AssertionError("invalid state " + state);
            };
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy