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

cn.wjybxx.dson.text.DsonTextReader Maven / Gradle / Ivy

The 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.text;

import cn.wjybxx.base.CollectionUtils;
import cn.wjybxx.base.pool.ConcurrentObjectPool;
import cn.wjybxx.base.time.TimeUtils;
import cn.wjybxx.dson.*;
import cn.wjybxx.dson.internal.DsonInternals;
import cn.wjybxx.dson.io.DsonIOException;
import cn.wjybxx.dson.types.*;

import java.io.Reader;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.util.ArrayDeque;
import java.util.HexFormat;
import java.util.List;
import java.util.Objects;

/**
 * 在二进制下,写入的顺序是: type-name-value
 * 但在文本格式下,写入的顺序是:name-type-value
 * 但我们要为用户提供一致的api,即对上层表现为二进制相同的读写顺序,因此我们需要将name缓存下来,直到用户调用readName。
 * 另外,我们只有先读取了value的token之后,才可以返回数据的类型{@link DsonType},
 * 因此 name-type-value 通常是在一次readType中完成。
 * 

* 另外,分隔符也需要压栈,以验证用户输入的正确性。 * * @author wjybxx * date - 2023/6/2 */ public final class DsonTextReader extends AbstractDsonReader { private static final List VALUE_SEPARATOR_TOKENS = List.of(DsonTokenType.COMMA, DsonTokenType.END_OBJECT, DsonTokenType.END_ARRAY); private static final DsonToken TOKEN_BEGIN_HEADER = new DsonToken(DsonTokenType.BEGIN_HEADER, "@{", -1); private static final DsonToken TOKEN_CLASSNAME = new DsonToken(DsonTokenType.UNQUOTE_STRING, DsonHeader.NAMES_CLASS_NAME, -1); private static final DsonToken TOKEN_COLON = new DsonToken(DsonTokenType.COLON, ":", -1); private static final DsonToken TOKEN_END_OBJECT = new DsonToken(DsonTokenType.END_OBJECT, "}", -1); private DsonScanner scanner; private String nextName; /** 未声明为DsonValue,避免再拆装箱 */ private Object nextValue; private boolean marking; private final ArrayDeque pushedTokenQueue = new ArrayDeque<>(6); private final ArrayDeque markedTokenQueue = new ArrayDeque<>(6); public DsonTextReader(DsonTextReaderSettings settings, CharSequence dsonString) { this(settings, new DsonScanner(dsonString)); } public DsonTextReader(DsonTextReaderSettings settings, Reader reader) { this(settings, new DsonScanner(DsonCharStream.newBufferedCharStream(reader, settings.autoClose))); } public DsonTextReader(DsonTextReaderSettings settings, Reader reader, boolean autoClose) { this(settings, new DsonScanner(DsonCharStream.newBufferedCharStream(reader, autoClose))); } public DsonTextReader(DsonTextReaderSettings settings, DsonScanner scanner) { super(settings); this.scanner = Objects.requireNonNull(scanner); Context context = newContext(null, DsonContextType.TOP_LEVEL, null); setContext(context); } /** * 用于动态指定成员数据类型 * 1.这对于精确解析数组元素和Object的字段十分有用 -- 比如解析一个{@code Vector3}的时候就可以指定字段的默认类型为float。 * 2.辅助方法见:{@link DsonTexts#clsNameTokenOfType(DsonType)} */ public void setCompClsNameToken(DsonToken dsonToken) { getContext().compClsNameToken = dsonToken; } @Override public DsonTextReaderSettings getSettings() { return (DsonTextReaderSettings) settings; } @Override protected Context getContext() { return (Context) super.getContext(); } @Override public void close() { Context context = getContext(); setContext(null); while (context != null) { Context parent = context.getParent(); contextPool.release(context); context = parent; } if (scanner != null) { scanner.close(); scanner = null; } pushedTokenQueue.clear(); nextName = null; nextValue = null; marking = false; markedTokenQueue.clear(); super.close(); } // region token private DsonToken popToken() { if (pushedTokenQueue.isEmpty()) { DsonToken dsonToken = scanner.nextToken(false); if (marking) { markedTokenQueue.addLast(dsonToken); } return dsonToken; } else { return pushedTokenQueue.pop(); } } private DsonToken skipToken() { if (pushedTokenQueue.isEmpty()) { return scanner.nextToken(true); } return pushedTokenQueue.pop(); } private void pushToken(DsonToken token) { Objects.requireNonNull(token); pushedTokenQueue.push(token); } private void pushNextValue(Object nextValue) { this.nextValue = Objects.requireNonNull(nextValue); } private Object popNextValue() { Object r = this.nextValue; this.nextValue = null; return r; } private void pushNextName(String nextName) { this.nextName = Objects.requireNonNull(nextName); } private String popNextName() { String r = this.nextName; this.nextName = null; return r; } // endregion // region state @Override public DsonType readDsonType() { Context context = this.getContext(); checkReadDsonTypeState(context); DsonType dsonType = readDsonTypeOfToken(); this.currentDsonType = dsonType; this.currentWireType = WireType.VARINT; this.currentName = INVALID_NAME; onReadDsonType(context, dsonType); if (dsonType == DsonType.HEADER) { context.headerCount++; } else { context.count++; } return dsonType; } @Override public DsonType peekDsonType() { Context context = this.getContext(); checkReadDsonTypeState(context); ArrayDeque pushedTokenQueue = this.pushedTokenQueue; ArrayDeque markedTokenQueue = this.markedTokenQueue; marking = true; markedTokenQueue.addAll(pushedTokenQueue); // 保存既有token DsonType dsonType = readDsonTypeOfToken(); popNextName(); // 丢弃临时数据 popNextValue(); pushedTokenQueue.clear(); pushedTokenQueue.addAll(markedTokenQueue); markedTokenQueue.clear(); marking = false; return dsonType; } /** * 两个职责: * 1.校验token在上下文中的正确性 -- 上层会校验DsonType的合法性 * 2.将合法的token转换为dson的键值对(或值) *

* 在读取valueToken时遇见 { 或 [ 时要判断是否是内置结构体,如果是内置结构体,要预读为值,而不是返回beginXXX; * 如果不是内置结构体,如果是 '@className' 形式声明的类型,要伪装成 {clsName: $className} 的token流,使得上层可按照相同的方式解析。 * '@clsName' 本质是简化书写的语法糖。 */ private DsonType readDsonTypeOfToken() { // 丢弃旧值 popNextName(); popNextValue(); Context context = getContext(); // 统一处理逗号分隔符,顶层对象之间可不写分隔符 if (context.count > 0) { DsonToken nextToken = popToken(); if (context.contextType != DsonContextType.TOP_LEVEL) { verifyTokenType(context, nextToken, VALUE_SEPARATOR_TOKENS); } if (nextToken.type == DsonTokenType.COMMA) { // 禁止末尾逗号 DsonToken nnToken = popToken(); pushToken(nnToken); if (nnToken.type == DsonTokenType.END_OBJECT || nnToken.type == DsonTokenType.END_ARRAY) { throw DsonIOException.invalidTokenType(context.contextType, nextToken); } } else { pushToken(nextToken); } } // object/header 需要先读取 name和冒号,但object可能出现header if (context.contextType == DsonContextType.OBJECT || context.contextType == DsonContextType.HEADER) { DsonToken nameToken = popToken(); switch (nameToken.type) { case STRING, UNQUOTE_STRING -> { pushNextName(nameToken.stringValue()); } case BEGIN_HEADER -> { if (context.contextType == DsonContextType.HEADER) { throw DsonIOException.containsHeaderDirectly(nameToken); } ensureCountIsZero(context, nameToken); pushNextValue(nameToken); return DsonType.HEADER; } case END_OBJECT -> { return DsonType.END_OF_OBJECT; } default -> { throw DsonIOException.invalidTokenType(context.contextType, nameToken, List.of(DsonTokenType.STRING, DsonTokenType.UNQUOTE_STRING, DsonTokenType.END_OBJECT)); } } // 下一个应该是冒号 DsonToken colonToken = popToken(); verifyTokenType(context, colonToken, DsonTokenType.COLON); } // 走到这里,表示 top/object/header/array 读值 DsonToken valueToken = popToken(); return switch (valueToken.type) { case INT32 -> { pushNextValue(valueToken.value); yield DsonType.INT32; } case INT64 -> { pushNextValue(valueToken.value); yield DsonType.INT64; } case FLOAT -> { pushNextValue(valueToken.value); yield DsonType.FLOAT; } case DOUBLE -> { pushNextValue(valueToken.value); yield DsonType.DOUBLE; } case BOOL -> { pushNextValue(valueToken.value); yield DsonType.BOOL; } case STRING -> { pushNextValue(valueToken.stringValue()); yield DsonType.STRING; } case NULL -> { pushNextValue(DsonNull.NULL); yield DsonType.NULL; } case BINARY -> { pushNextValue(valueToken.value); yield DsonType.BINARY; } case BUILTIN_STRUCT -> parseAbbreviatedStruct(context, valueToken); case UNQUOTE_STRING -> parseUnquoteStringToken(context, valueToken); case BEGIN_OBJECT -> parseBeginObjectToken(context, valueToken); case BEGIN_ARRAY -> parseBeginArrayToken(context, valueToken); case BEGIN_HEADER -> { // object的header已经处理,这里只有topLevel和array可以再出现header if (context.contextType.isObjectLike()) { throw DsonIOException.invalidTokenType(context.contextType, valueToken); } ensureCountIsZero(context, valueToken); // pushNextValue(valueToken); yield DsonType.HEADER; } case END_ARRAY -> { // endArray 只能在数组上下文出现;Array是在读取下一个值的时候结束;而Object必须在读取下一个name的时候结束 if (context.contextType == DsonContextType.ARRAY) { yield DsonType.END_OF_OBJECT; } throw DsonIOException.invalidTokenType(context.contextType, valueToken); } case EOF -> { // eof 只能在顶层上下文出现 if (context.contextType == DsonContextType.TOP_LEVEL) { yield DsonType.END_OF_OBJECT; } throw DsonIOException.invalidTokenType(context.contextType, valueToken); } default -> { throw DsonIOException.invalidTokenType(context.contextType, valueToken); } }; } /** 字符串默认解析规则 */ private DsonType parseUnquoteStringToken(Context context, DsonToken valueToken) { String unquotedString = valueToken.stringValue(); // 处理header的特殊属性依赖 if (context.contextType == DsonContextType.HEADER) { switch (nextName) { case DsonHeader.NAMES_CLASS_NAME -> { pushNextValue(unquotedString); return DsonType.STRING; } case DsonHeader.NAMES_LOCAL_ID -> { return parseLocalId(unquotedString); } } } // 处理类型传递 if (context.compClsNameToken != null) { switch (context.compClsNameToken.stringValue()) { case DsonTexts.LABEL_INT32 -> { pushNextValue(DsonTexts.parseInt32(unquotedString)); return DsonType.INT32; } case DsonTexts.LABEL_INT64 -> { pushNextValue(DsonTexts.parseInt64(unquotedString)); return DsonType.INT64; } case DsonTexts.LABEL_FLOAT -> { pushNextValue(DsonTexts.parseFloat(unquotedString)); return DsonType.FLOAT; } case DsonTexts.LABEL_DOUBLE -> { pushNextValue(DsonTexts.parseDouble(unquotedString)); return DsonType.DOUBLE; } case DsonTexts.LABEL_BOOL -> { pushNextValue(DsonTexts.parseBool(unquotedString)); return DsonType.BOOL; } case DsonTexts.LABEL_STRING -> { pushNextValue(unquotedString); return DsonType.STRING; } case DsonTexts.LABEL_BINARY -> { byte[] bytes = HexFormat.of().parseHex(unquotedString); pushNextValue(bytes); // 直接压入bytes return DsonType.BINARY; } } } // 处理特殊值解析 boolean isTrueString = "true".equals(unquotedString); if (isTrueString || "false".equals(unquotedString)) { pushNextValue(isTrueString); return DsonType.BOOL; } if ("null".equals(unquotedString)) { pushNextValue(DsonNull.NULL); return DsonType.NULL; } if (DsonTexts.isParsable(unquotedString)) { pushNextValue(DsonTexts.parseDouble(unquotedString)); return DsonType.DOUBLE; } pushNextValue(unquotedString); return DsonType.STRING; } private DsonType parseLocalId(String unquotedString) { switch (getSettings().localIdType) { case INT32 -> { pushNextValue(DsonTexts.parseInt32(unquotedString)); return DsonType.INT32; } case INT64 -> { pushNextValue(DsonTexts.parseInt64(unquotedString)); return DsonType.INT64; } default -> { pushNextValue(unquotedString); return DsonType.STRING; } } } /** 处理内置结构体的单值语法糖 */ private DsonType parseAbbreviatedStruct(Context context, final DsonToken valueToken) { // 1.className不能出现在topLevel,topLevel只能出现header结构体 @{} if (context.contextType == DsonContextType.TOP_LEVEL) { throw DsonIOException.invalidTokenType(context.contextType, valueToken); } // 2.object和array的className会在beginObject和beginArray的时候转换为结构体 @{} // 因此这里只能出现内置结构体的简写形式 String clsName = valueToken.stringValue(); if (DsonTexts.LABEL_PTR.equals(clsName)) {// @ptr localId DsonToken nextToken = popToken(); ensureStringsToken(context, nextToken); pushNextValue(new ObjectPtr(nextToken.stringValue())); return DsonType.POINTER; } if (DsonTexts.LABEL_LITE_PTR.equals(clsName)) { // @lptr localId DsonToken nextToken = popToken(); ensureStringsToken(context, nextToken); long localId = DsonTexts.parseInt64(nextToken.stringValue()); pushNextValue(new ObjectLitePtr(localId)); return DsonType.LITE_POINTER; } if (DsonTexts.LABEL_DATETIME.equals(clsName)) { // @dt uuuu-MM-dd'T'HH:mm:ss LocalDateTime dateTime = ExtDateTime.parseDateTime(scanStringUtilComma()); pushNextValue(ExtDateTime.ofDateTime(dateTime)); return DsonType.DATETIME; } if (DsonTexts.LABEL_TIMESTAMP.equals(clsName)) { // @ts seconds DsonToken nextToken = popToken(); ensureStringsToken(context, nextToken); Timestamp timestamp = Timestamp.parse(nextToken.stringValue()); pushNextValue(timestamp); return DsonType.TIMESTAMP; } throw DsonIOException.invalidTokenType(context.contextType, valueToken); } private DsonToken popHeaderToken(Context context) { DsonToken headerToken = popToken(); if (isHeaderOrBuiltStructToken(headerToken)) { return headerToken; } pushToken(headerToken); return null; } /** 处理内置结构体 */ private DsonType parseBeginObjectToken(Context context, final DsonToken valueToken) { DsonToken headerToken = popHeaderToken(context); if (headerToken == null) { pushNextValue(valueToken); return DsonType.OBJECT; } if (headerToken.type != DsonTokenType.BUILTIN_STRUCT) { // 转换SimpleHeader为标准Header,token需要push以供context保存 escapeHeaderAndPush(headerToken); pushNextValue(valueToken); return DsonType.OBJECT; } // 内置结构体 String clsName = headerToken.stringValue(); return switch (clsName) { case DsonTexts.LABEL_PTR -> { pushNextValue(scanPtr(context)); yield DsonType.POINTER; } case DsonTexts.LABEL_LITE_PTR -> { pushNextValue(scanLitePtr(context)); yield DsonType.LITE_POINTER; } case DsonTexts.LABEL_DATETIME -> { pushNextValue(scanDateTime(context)); yield DsonType.DATETIME; } case DsonTexts.LABEL_TIMESTAMP -> { pushNextValue(scanTimestamp(context)); yield DsonType.TIMESTAMP; } default -> { pushToken(headerToken); // 非Object形式内置结构体 // pushNextValue(valueToken); yield DsonType.OBJECT; } }; } /** 处理内置元组 */ private DsonType parseBeginArrayToken(Context context, final DsonToken valueToken) { DsonToken headerToken = popHeaderToken(context); if (headerToken == null) { pushNextValue(valueToken); return DsonType.ARRAY; } if (headerToken.type != DsonTokenType.BUILTIN_STRUCT) { // 转换SimpleHeader为标准Header,token需要push以供context保存 escapeHeaderAndPush(headerToken); pushNextValue(valueToken); return DsonType.ARRAY; } // 内置元组 -- 已尽皆删除... pushToken(headerToken); // pushNextValue(valueToken); return DsonType.ARRAY; } private void escapeHeaderAndPush(DsonToken headerToken) { // 如果header不是结构体,则封装为结构体,注意...要反序压栈 if (headerToken.type == DsonTokenType.BEGIN_HEADER) { pushToken(headerToken); } else { pushToken(TOKEN_END_OBJECT); pushToken(new DsonToken(DsonTokenType.STRING, headerToken.stringValue(), -1)); pushToken(TOKEN_COLON); pushToken(TOKEN_CLASSNAME); pushToken(TOKEN_BEGIN_HEADER); } } // region 内置结构体语法 private ObjectPtr scanPtr(Context context) { String namespace = null; String localId = null; byte type = 0; byte policy = 0; DsonToken keyToken; while ((keyToken = popToken()).type != DsonTokenType.END_OBJECT) { // key必须是字符串 ensureStringsToken(context, keyToken); // 下一个应该是冒号 DsonToken colonToken = popToken(); verifyTokenType(context, colonToken, DsonTokenType.COLON); // 根据name校验 DsonToken valueToken = popToken(); switch (keyToken.stringValue()) { case ObjectPtr.NAMES_NAMESPACE -> { ensureStringsToken(context, valueToken); namespace = valueToken.stringValue(); } case ObjectPtr.NAMES_LOCAL_ID -> { ensureStringsToken(context, valueToken); localId = valueToken.stringValue(); } case ObjectPtr.NAMES_TYPE -> { verifyTokenType(context, valueToken, DsonTokenType.UNQUOTE_STRING); type = Byte.parseByte(valueToken.stringValue()); } case ObjectPtr.NAMES_POLICY -> { verifyTokenType(context, valueToken, DsonTokenType.UNQUOTE_STRING); policy = Byte.parseByte(valueToken.stringValue()); } default -> { throw new DsonIOException("invalid ptr fieldName: " + keyToken.stringValue()); } } checkSeparator(context); } return new ObjectPtr(localId, namespace, type, policy); } private ObjectLitePtr scanLitePtr(Context context) { String namespace = null; long localId = 0; byte type = 0; byte policy = 0; DsonToken keyToken; while ((keyToken = popToken()).type != DsonTokenType.END_OBJECT) { // key必须是字符串 ensureStringsToken(context, keyToken); // 下一个应该是冒号 DsonToken colonToken = popToken(); verifyTokenType(context, colonToken, DsonTokenType.COLON); // 根据name校验 DsonToken valueToken = popToken(); switch (keyToken.stringValue()) { case ObjectPtr.NAMES_NAMESPACE -> { ensureStringsToken(context, valueToken); namespace = valueToken.stringValue(); } case ObjectPtr.NAMES_LOCAL_ID -> { verifyTokenType(context, valueToken, DsonTokenType.UNQUOTE_STRING); localId = DsonTexts.parseInt64(valueToken.stringValue()); } case ObjectPtr.NAMES_TYPE -> { verifyTokenType(context, valueToken, DsonTokenType.UNQUOTE_STRING); type = Byte.parseByte(valueToken.stringValue()); } case ObjectPtr.NAMES_POLICY -> { verifyTokenType(context, valueToken, DsonTokenType.UNQUOTE_STRING); policy = Byte.parseByte(valueToken.stringValue()); } default -> { throw new DsonIOException("invalid lptr fieldName: " + keyToken.stringValue()); } } checkSeparator(context); } return new ObjectLitePtr(localId, namespace, type, policy); } private Timestamp scanTimestamp(Context context) { long seconds = 0; int nanos = 0; DsonToken keyToken; while ((keyToken = popToken()).type != DsonTokenType.END_OBJECT) { // key必须是字符串 ensureStringsToken(context, keyToken); // 下一个应该是冒号 DsonToken colonToken = popToken(); verifyTokenType(context, colonToken, DsonTokenType.COLON); // 根据name校验 switch (keyToken.stringValue()) { case Timestamp.NAMES_SECONDS -> { DsonToken valueToken = popToken(); ensureStringsToken(context, valueToken); seconds = DsonTexts.parseInt64(valueToken.stringValue()); } case Timestamp.NAMES_NANOS -> { DsonToken valueToken = popToken(); ensureStringsToken(context, valueToken); nanos = DsonTexts.parseInt32(valueToken.stringValue()); } case Timestamp.NAMES_MILLIS -> { DsonToken valueToken = popToken(); ensureStringsToken(context, valueToken); int millis = DsonTexts.parseInt32(valueToken.stringValue()); Timestamp.validateMillis(millis); nanos = millis * (int) TimeUtils.NANOS_PER_MILLI; } default -> { throw new DsonIOException("invalid datetime fieldName: " + keyToken.stringValue()); } } checkSeparator(context); } return new Timestamp(seconds, nanos); } private ExtDateTime scanDateTime(Context context) { LocalDate date = LocalDate.EPOCH; LocalTime time = LocalTime.MIN; int nanos = 0; int offset = 0; byte enables = 0; DsonToken keyToken; while ((keyToken = popToken()).type != DsonTokenType.END_OBJECT) { // key必须是字符串 ensureStringsToken(context, keyToken); // 下一个应该是冒号 DsonToken colonToken = popToken(); verifyTokenType(context, colonToken, DsonTokenType.COLON); // 根据name校验 switch (keyToken.stringValue()) { case ExtDateTime.NAMES_DATE -> { String dateString = scanStringUtilComma(); date = ExtDateTime.parseDate(dateString); enables |= ExtDateTime.MASK_DATE; } case ExtDateTime.NAMES_TIME -> { String timeString = scanStringUtilComma(); time = ExtDateTime.parseTime(timeString); enables |= ExtDateTime.MASK_TIME; } case ExtDateTime.NAMES_OFFSET -> { String offsetString = scanStringUtilComma(); offset = ExtDateTime.parseOffset(offsetString); enables |= ExtDateTime.MASK_OFFSET; } case ExtDateTime.NAMES_NANOS -> { DsonToken valueToken = popToken(); ensureStringsToken(context, valueToken); nanos = DsonTexts.parseInt32(valueToken.stringValue()); } case ExtDateTime.NAMES_MILLIS -> { DsonToken valueToken = popToken(); ensureStringsToken(context, valueToken); int millis = DsonTexts.parseInt32(valueToken.stringValue()); Timestamp.validateMillis(millis); nanos = millis * (int) TimeUtils.NANOS_PER_MILLI; } default -> { throw new DsonIOException("invalid datetime fieldName: " + keyToken.stringValue()); } } checkSeparator(context); } long seconds = LocalDateTime.of(date, time).toEpochSecond(ZoneOffset.UTC); return new ExtDateTime(seconds, nanos, offset, enables); } /** 扫描string,直到遇见逗号或结束符 */ private String scanStringUtilComma() { StringBuilder sb = new StringBuilder(12); while (true) { DsonToken valueToken = popToken(); switch (valueToken.type) { case COMMA, END_OBJECT, END_ARRAY -> { pushToken(valueToken); return sb.toString(); } case STRING, UNQUOTE_STRING, COLON -> { sb.append(valueToken.stringValue()); } default -> { throw DsonIOException.invalidTokenType(getContextType(), valueToken); } } } } private void checkSeparator(Context context) { // 每读取一个值,判断下分隔符,尾部最多只允许一个逗号 -- 这里在尾部更容易处理 DsonToken keyToken; if ((keyToken = popToken()).type == DsonTokenType.COMMA && (keyToken = popToken()).type == DsonTokenType.COMMA) { throw DsonIOException.invalidTokenType(context.contextType, keyToken); } else { pushToken(keyToken); } } // endregion /** header不可以在中途出现 */ private static void ensureCountIsZero(Context context, DsonToken headerToken) { if (context.count > 0) { throw DsonIOException.invalidTokenType(context.contextType, headerToken, List.of(DsonTokenType.STRING, DsonTokenType.UNQUOTE_STRING, DsonTokenType.END_OBJECT)); } } private static void ensureStringsToken(Context context, DsonToken token) { if (token.type != DsonTokenType.STRING && token.type != DsonTokenType.UNQUOTE_STRING) { throw DsonIOException.invalidTokenType(context.contextType, token, List.of(DsonTokenType.STRING, DsonTokenType.UNQUOTE_STRING)); } } private static boolean isHeaderOrBuiltStructToken(DsonToken token) { return token.type == DsonTokenType.BUILTIN_STRUCT || token.type == DsonTokenType.SIMPLE_HEADER || token.type == DsonTokenType.BEGIN_HEADER; } private static void verifyTokenType(Context context, DsonToken token, DsonTokenType expected) { if (token.type != expected) { throw DsonIOException.invalidTokenType(context.contextType, token, List.of(expected)); } } private static void verifyTokenType(Context context, DsonToken token, List expected) { if (!CollectionUtils.containsRef(expected, token.type)) { throw DsonIOException.invalidTokenType(context.contextType, token, expected); } } @Override protected void doReadName() { if (settings.enableFieldIntern) { currentName = Dsons.internField(popNextName()); } else { currentName = Objects.requireNonNull(popNextName()); } } // endregion // region 简单值 @Override public Number readNumber(String name) { // 重写以减少拆装箱 advanceToValueState(name, null); return switch (currentDsonType) { case INT32, INT64, FLOAT, DOUBLE -> { Number number = (Number) popNextValue(); Objects.requireNonNull(number); setNextState(); yield number; } default -> throw DsonIOException.dsonTypeMismatch(DsonType.DOUBLE, currentDsonType); }; } @Override protected int doReadInt32() { Number number = (Number) popNextValue(); Objects.requireNonNull(number); return number.intValue(); } @Override protected long doReadInt64() { Number number = (Number) popNextValue(); Objects.requireNonNull(number); return number.longValue(); } @Override protected float doReadFloat() { Number number = (Number) popNextValue(); Objects.requireNonNull(number); return number.floatValue(); } @Override protected double doReadDouble() { Number number = (Number) popNextValue(); Objects.requireNonNull(number); return number.doubleValue(); } @Override protected boolean doReadBool() { Boolean value = (Boolean) popNextValue(); Objects.requireNonNull(value); return value; } @Override protected String doReadString() { String value = (String) popNextValue(); Objects.requireNonNull(value); return value; } @Override protected void doReadNull() { Object value = popNextValue(); assert value == DsonNull.NULL; } @Override protected Binary doReadBinary() { byte[] bytes = (byte[]) Objects.requireNonNull(popNextValue()); return Binary.unsafeWrap(bytes); } @Override protected ObjectPtr doReadPtr() { return (ObjectPtr) Objects.requireNonNull(popNextValue()); } @Override protected ObjectLitePtr doReadLitePtr() { return (ObjectLitePtr) Objects.requireNonNull(popNextValue()); } @Override protected ExtDateTime doReadDateTime() { return (ExtDateTime) Objects.requireNonNull(popNextValue()); } @Override protected Timestamp doReadTimestamp() { return (Timestamp) Objects.requireNonNull(popNextValue()); } // endregion // region 容器 @Override protected void doReadStartContainer(DsonContextType contextType, DsonType dsonType) { Context newContext = newContext(getContext(), contextType, dsonType); // newContext.beginToken = popNextValue(); newContext.name = currentName; this.recursionDepth++; setContext(newContext); } @Override protected void doReadEndContainer() { Context context = getContext(); // 恢复上下文 recoverDsonType(context); this.recursionDepth--; setContext(context.parent); returnContext(context); } // endregion // region 特殊接口 @Override protected void doSkipName() { // 名字早已读取 popNextName(); } @Override protected void doSkipValue() { popNextValue(); switch (currentDsonType) { case HEADER, OBJECT, ARRAY -> skipStack(1); } } @Override protected void doSkipToEndOfObject() { DsonToken endToken; if (isAtType()) { endToken = skipStack(1); } else { skipName(); endToken = switch (currentDsonType) { // 嵌套对象 case HEADER, OBJECT, ARRAY -> skipStack(2); default -> skipStack(1); }; } pushToken(endToken); } /** @return 触发结束的token */ private DsonToken skipStack(int stack) { while (stack > 0) { DsonToken token = marking ? popToken() : skipToken(); switch (token.type) { case BEGIN_ARRAY, BEGIN_OBJECT, BEGIN_HEADER -> stack++; case END_ARRAY, END_OBJECT -> { if (--stack == 0) { return token; } } case EOF -> { throw DsonIOException.invalidTokenType(getContextType(), token); } } } throw new AssertionError(); } @Override protected byte[] doReadValueAsBytes() { // Text的Reader和Writer实现最好相同,要么都不支持,要么都支持 throw new UnsupportedOperationException(); } // endregion // region context private static final ConcurrentObjectPool contextPool = new ConcurrentObjectPool<>(Context::new, Context::reset, DsonInternals.CONTEXT_POOL_SIZE); private static Context newContext(Context parent, DsonContextType contextType, DsonType dsonType) { Context context = contextPool.acquire(); context.init(parent, contextType, dsonType); return context; } private static void returnContext(Context context) { contextPool.release(context); } protected static class Context extends AbstractDsonReader.Context { /** header只可触发一次流程 */ int headerCount = 0; /** 元素计数,判断冒号 */ int count; /** 数组/Object成员的类型 - token类型可直接复用;header的该属性是用于注释外层对象的 */ DsonToken compClsNameToken; public Context() { } public void reset() { super.reset(); headerCount = 0; count = 0; compClsNameToken = null; } @Override public Context getParent() { return (Context) parent; } } // endregion }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy