This is an automated email from the ASF dual-hosted git repository. sruehl pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/develop by this push: new 0c5f2ae plc4go: first draft of WriterBufferJsonBased.go 0c5f2ae is described below commit 0c5f2ae2f678cd12ad1dd0daf7a8b8ada22712b5 Author: Sebastian Rühl <sru...@apache.org> AuthorDate: Wed Apr 21 00:38:14 2021 +0200 plc4go: first draft of WriterBufferJsonBased.go + refactored reader and writers --- .../resources/templates/go/model-template.go.ftlh | 12 +- go.mod | 2 +- go.sum | 2 + .../plc4go/s7/readwrite/model/COTPPacket.go | 8 +- plc4go/internal/plc4go/s7/s7Io_test.go | 217 +++++++++++++++---- plc4go/internal/plc4go/spi/utils/Buffer.go | 85 ++++++++ .../plc4go/spi/utils/ReadBufferXmlBased.go | 55 ++--- .../plc4go/spi/utils/WriteBufferBoxBased.go | 52 ++--- .../plc4go/spi/utils/WriteBufferJsonBased.go | 232 +++++++++++++++++++++ .../plc4go/spi/utils/WriteBufferXmlBased.go | 106 +++------- plc4go/internal/plc4go/spi/utils/bufferCommons.go | 103 +++++++++ 11 files changed, 689 insertions(+), 185 deletions(-) diff --git a/build-utils/language-go/src/main/resources/templates/go/model-template.go.ftlh b/build-utils/language-go/src/main/resources/templates/go/model-template.go.ftlh index 5af59d7..5d138f5 100644 --- a/build-utils/language-go/src/main/resources/templates/go/model-template.go.ftlh +++ b/build-utils/language-go/src/main/resources/templates/go/model-template.go.ftlh @@ -544,7 +544,7 @@ func ${type.name}Parse(io utils.ReadBuffer<#if type.parserArguments?has_content> <#assign arrayField = field> // Array field (${arrayField.name}) - io.PullContext("${arrayField.name}") + io.PullContext("${arrayField.name}", utils.WithRenderAsList(true)) <#-- Only update curPos if the length expression uses it --> <#if arrayField.loopExpression.contains("curPos")> curPos = io.GetPos() - startPos<@emitImport import="io" /> @@ -598,7 +598,7 @@ func ${type.name}Parse(io utils.ReadBuffer<#if type.parserArguments?has_content> </#if> } </#if> - io.CloseContext("${arrayField.name}") + io.CloseContext("${arrayField.name}", utils.WithRenderAsList(true)) <#break> <#case "checksum"> <#assign checksumField = field> @@ -691,7 +691,7 @@ func ${type.name}Parse(io utils.ReadBuffer<#if type.parserArguments?has_content> <#break> <#case "manualArray"> <#assign manualArrayField = field> - io.PullContext("${manualArrayField.name}") + io.PullContext("${manualArrayField.name}", utils.WithRenderAsList(true)) // Manual Array Field (${manualArrayField.name}) <#-- Only update curPos if the length expression uses it --> <#if manualArrayField.loopExpression.contains("curPos")> @@ -747,7 +747,7 @@ func ${type.name}Parse(io utils.ReadBuffer<#if type.parserArguments?has_content> ${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = _${manualArrayField.name}List.toArray(new ${helper.getLanguageTypeNameForField(manualArrayField)}[0]) </#if> </#if> - io.CloseContext("${manualArrayField.name}") + io.CloseContext("${manualArrayField.name}", utils.WithRenderAsList(true)) <#break> <#case "manual"> <#assign manualField = field> @@ -1043,11 +1043,11 @@ func (m *${type.name}) Serialize(io utils.WriteBuffer<#if helper.getSerializerAr // Manual Array Field (${manualArrayField.name}) if m.${manualArrayField.name?cap_first} != nil { - io.PushContext("${manualArrayField.name}") + io.PushContext("${manualArrayField.name}", utils.WithRenderAsList(true)) for(${helper.getLanguageTypeNameForField(field)} element : m.${manualArrayField.name?cap_first}) { ${helper.toSerializationExpression(manualArrayField, manualArrayField.serializeExpression, type.parserArguments)} } - io.PushContext("${manualArrayField.name}") + io.PopContext("${manualArrayField.name}", utils.WithRenderAsList(true)) } <#break> <#case "manual"> diff --git a/go.mod b/go.mod index eebd510..751a141 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,6 @@ module github.com/apache/plc4x go 1.15 require ( - github.com/apache/plc4x/plc4go v0.0.0-20210420140858-e7f2f4c6b117 // indirect + github.com/apache/plc4x/plc4go v0.0.0-20210420175605-7ec5b56fe1cf // indirect github.com/sirupsen/logrus v1.7.0 // indirect ) diff --git a/go.sum b/go.sum index e36d6ad..c53de2f 100644 --- a/go.sum +++ b/go.sum @@ -96,6 +96,8 @@ github.com/apache/plc4x/plc4go v0.0.0-20210419213911-a28fac5a883e h1:RH0AQ+AnzYJ github.com/apache/plc4x/plc4go v0.0.0-20210419213911-a28fac5a883e/go.mod h1:NqpWaMMhsu3sTm418XwsUWgmY7e2zjgpRMyddBUwmGk= github.com/apache/plc4x/plc4go v0.0.0-20210420140858-e7f2f4c6b117 h1:aJkJp07IONjywarB9o0DlWyFRwPJIgn+Nfn1jxJz86s= github.com/apache/plc4x/plc4go v0.0.0-20210420140858-e7f2f4c6b117/go.mod h1:NqpWaMMhsu3sTm418XwsUWgmY7e2zjgpRMyddBUwmGk= +github.com/apache/plc4x/plc4go v0.0.0-20210420175605-7ec5b56fe1cf h1:HYsSjhzqXX2CWIP9iF+or7q3bLJEvB3XBx146pejQ04= +github.com/apache/plc4x/plc4go v0.0.0-20210420175605-7ec5b56fe1cf/go.mod h1:NqpWaMMhsu3sTm418XwsUWgmY7e2zjgpRMyddBUwmGk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= diff --git a/plc4go/internal/plc4go/s7/readwrite/model/COTPPacket.go b/plc4go/internal/plc4go/s7/readwrite/model/COTPPacket.go index a5b5c8b..fca65b6 100644 --- a/plc4go/internal/plc4go/s7/readwrite/model/COTPPacket.go +++ b/plc4go/internal/plc4go/s7/readwrite/model/COTPPacket.go @@ -159,7 +159,7 @@ func COTPPacketParse(io utils.ReadBuffer, cotpLen uint16) (*COTPPacket, error) { } // Array field (parameters) - io.PullContext("parameters") + io.PullContext("parameters", utils.WithRenderAsList(true)) curPos = io.GetPos() - startPos // Length array parameters := make([]*COTPParameter, 0) @@ -173,7 +173,7 @@ func COTPPacketParse(io utils.ReadBuffer, cotpLen uint16) (*COTPPacket, error) { parameters = append(parameters, _item) curPos = io.GetPos() - startPos } - io.CloseContext("parameters") + io.CloseContext("parameters", utils.WithRenderAsList(true)) // Optional Field (payload) (Can be skipped, if a given expression evaluates to false) curPos = io.GetPos() - startPos @@ -223,14 +223,14 @@ func (m *COTPPacket) SerializeParent(io utils.WriteBuffer, child ICOTPPacket, se // Array Field (parameters) if m.Parameters != nil { - io.PushContext("parameters") + io.PushContext("parameters", utils.WithRenderAsList(true)) for _, _element := range m.Parameters { _elementErr := _element.Serialize(io) if _elementErr != nil { return errors.Wrap(_elementErr, "Error serializing 'parameters' field") } } - io.PopContext("parameters") + io.PopContext("parameters", utils.WithRenderAsList(true)) } // Optional Field (payload) (Can be skipped, if the value is null) diff --git a/plc4go/internal/plc4go/s7/s7Io_test.go b/plc4go/internal/plc4go/s7/s7Io_test.go index 33cec3c..e803ab3 100644 --- a/plc4go/internal/plc4go/s7/s7Io_test.go +++ b/plc4go/internal/plc4go/s7/s7Io_test.go @@ -43,6 +43,7 @@ func TestS7MessageBytes(t *testing.T) { wantString string wantStringSerialized string wantStringXml string + wantStringJson string wantDump string }{ { @@ -220,6 +221,126 @@ func TestS7MessageBytes(t *testing.T) { </payload> </TPKTPacket> `, + wantStringJson: ` +{ + "TPKTPacket": { + "len": 29, + "len__plc4x_bitLength": 16, + "len__plc4x_dataType": "uint", + "payload": { + "COTPPacket": { + "COTPPacketData": { + "eot": false, + "eot__plc4x_bitLength": 1, + "eot__plc4x_dataType": "bit", + "tpduRef": 13, + "tpduRef__plc4x_bitLength": 7, + "tpduRef__plc4x_dataType": "uint" + }, + "S7Message": { + "S7MessageResponseData": { + "errorClass": 0, + "errorClass__plc4x_bitLength": 8, + "errorClass__plc4x_dataType": "uint", + "errorCode": 0, + "errorCode__plc4x_bitLength": 8, + "errorCode__plc4x_dataType": "uint" + }, + "S7Parameter": { + "S7ParameterReadVarResponse": { + "numItems": 1, + "numItems__plc4x_bitLength": 8, + "numItems__plc4x_dataType": "uint" + }, + "parameterType": 4, + "parameterType__plc4x_bitLength": 8, + "parameterType__plc4x_dataType": "uint" + }, + "S7Payload": { + "S7PayloadReadVarResponse": { + "items": { + "S7VarPayloadDataItem": { + "data": { + "value": 1, + "value__plc4x_bitLength": 8, + "value__plc4x_dataType": "int" + }, + "dataLength": 1, + "dataLength__plc4x_bitLength": 16, + "dataLength__plc4x_dataType": "uint", + "padding": {}, + "returnCode": { + "DataTransportErrorCode": 255, + "DataTransportErrorCode__plc4x_bitLength": 8, + "DataTransportErrorCode__plc4x_dataType": "uint", + "DataTransportErrorCode__plc4x_stringRepresentation": "OK" + }, + "transportSize": { + "DataTransportSize": 3, + "DataTransportSize__plc4x_bitLength": 8, + "DataTransportSize__plc4x_dataType": "uint", + "DataTransportSize__plc4x_stringRepresentation": "BIT" + } + } + } + } + }, + "messageType": 3, + "messageType__plc4x_bitLength": 8, + "messageType__plc4x_dataType": "uint", + "parameterLength": 2, + "parameterLength__plc4x_bitLength": 16, + "parameterLength__plc4x_dataType": "uint", + "payloadLength": 5, + "payloadLength__plc4x_bitLength": 16, + "payloadLength__plc4x_dataType": "uint", + "protocolId": 50, + "protocolId__plc4x_bitLength": 8, + "protocolId__plc4x_dataType": "uint", + "reserved": 0, + "reserved__plc4x_bitLength": 16, + "reserved__plc4x_dataType": "uint", + "tpduReference": 11, + "tpduReference__plc4x_bitLength": 16, + "tpduReference__plc4x_dataType": "uint" + }, + "headerLength": 5, + "headerLength__plc4x_bitLength": 8, + "headerLength__plc4x_dataType": "uint", + "parameters": [ + { + "COTPParameter": { + "COTPParameterTpduSize": { + "tpduSize": { + "COTPTpduSize": 12, + "COTPTpduSize__plc4x_bitLength": 8, + "COTPTpduSize__plc4x_dataType": "int", + "COTPTpduSize__plc4x_stringRepresentation": "SIZE_4096" + } + }, + "parameterLength": 1, + "parameterLength__plc4x_bitLength": 8, + "parameterLength__plc4x_dataType": "uint", + "parameterType": 192, + "parameterType__plc4x_bitLength": 8, + "parameterType__plc4x_dataType": "uint" + } + } + ], + "tpduCode": 240, + "tpduCode__plc4x_bitLength": 8, + "tpduCode__plc4x_dataType": "uint" + } + }, + "protocolId": 3, + "protocolId__plc4x_bitLength": 8, + "protocolId__plc4x_dataType": "uint", + "reserved": 0, + "reserved__plc4x_bitLength": 8, + "reserved__plc4x_dataType": "uint" + } +} +`, wantDump: ` 00|03 00 00 1d 05 f0 0d c0 01 0c '..........' 10|32 03 00 00 00 0b 00 02 00 05 '2.........' @@ -229,47 +350,71 @@ func TestS7MessageBytes(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // Simple 2 String - tt.wantString = strings.Trim(tt.wantString, "\n") - if got := tt.args.debuggable.String(); got != tt.wantString { - t.Errorf("String() = '\n%v\n', want '\n%v\n'", got, tt.wantString) - } - // Simple 2 Box - boxWriter := utils.NewBoxedWriteBuffer() - if err := tt.args.debuggable.Serialize(boxWriter); err != nil { - t.Error(err) - } - tt.wantStringSerialized = strings.Trim(tt.wantStringSerialized, "\n") - if got := string(boxWriter.GetBox()); got != tt.wantStringSerialized { - t.Errorf("Serialize Boxed() = '\n%v\n', want '\n%v\n'", got, tt.wantStringSerialized) - } - // Simple 2 Xml - xmlWriteBuffer := utils.NewXmlWriteBuffer() - if err := tt.args.debuggable.Serialize(xmlWriteBuffer); err != nil { - t.Error(err) + { + // Simple 2 String + tt.wantString = strings.Trim(tt.wantString, "\n") + if got := tt.args.debuggable.String(); got != tt.wantString { + t.Errorf("String() = '\n%v\n', want '\n%v\n'", got, tt.wantString) + } } - tt.wantStringXml = strings.Trim(tt.wantStringXml, "\n") - if got := xmlWriteBuffer.GetXmlString(); got != tt.wantStringXml { - t.Errorf("Serialize Xml() = '\n%v\n', want '\n%v\n'", got, tt.wantStringXml) + { + // Simple 2 Box + boxWriter := utils.NewBoxedWriteBuffer() + if err := tt.args.debuggable.Serialize(boxWriter); err != nil { + t.Error(err) + } + tt.wantStringSerialized = strings.Trim(tt.wantStringSerialized, "\n") + if got := string(boxWriter.GetBox()); got != tt.wantStringSerialized { + t.Errorf("Serialize Boxed() = '\n%v\n', want '\n%v\n'", got, tt.wantStringSerialized) + } } - - // Simple Binary Serialize - buffer := utils.NewWriteBuffer() - if err := tt.args.debuggable.Serialize(buffer); err != nil { - t.Error(err) + { + // Simple 2 Xml + xmlWriteBuffer := utils.NewXmlWriteBuffer() + if err := tt.args.debuggable.Serialize(xmlWriteBuffer); err != nil { + t.Error(err) + } + tt.wantStringXml = strings.Trim(tt.wantStringXml, "\n") + if got := xmlWriteBuffer.GetXmlString(); got != tt.wantStringXml { + t.Errorf("Serialize Xml() = '\n%v\n', want '\n%v\n'", got, tt.wantStringXml) + } } - tt.wantDump = strings.Trim(tt.wantDump, "\n") - if got := utils.Dump(buffer.GetBytes()); !reflect.DeepEqual(got, tt.wantDump) { - t.Errorf("Serialize() = '\n%v\n', want '\n%v\n'", got, tt.wantDump) + { + // Simple 2 Json + jsonWriteBuffer := utils.NewJsonWriteBuffer() + if err := tt.args.debuggable.Serialize(jsonWriteBuffer); err != nil { + t.Error(err) + } + tt.wantStringJson = strings.Trim(tt.wantStringJson, "\n") + if got, err := jsonWriteBuffer.GetJsonString(); err != nil || strings.Trim(got, "\n") != tt.wantStringJson { + if err != nil { + t.Error(err) + } else { + t.Errorf("Serialize Json() = '\n%v\n', want '\n%v\n'", got, tt.wantStringJson) + } + } } - // and at least a roundtip - reader := strings.NewReader(tt.wantStringXml) - readBuffer := utils.NewXmlReadBuffer(reader) - if got, err := model.TPKTPacketParse(readBuffer); err != nil || !reflect.DeepEqual(got, tt.args.debuggable) { - if err != nil { + { + // Simple Binary Serialize + buffer := utils.NewWriteBuffer() + if err := tt.args.debuggable.Serialize(buffer); err != nil { t.Error(err) - } else { - t.Errorf("Roundtrip = '\n%v\n', want '\n%v\n'", got, tt.wantDump) + } + tt.wantDump = strings.Trim(tt.wantDump, "\n") + if got := utils.Dump(buffer.GetBytes()); !reflect.DeepEqual(got, tt.wantDump) { + t.Errorf("Serialize() = '\n%v\n', want '\n%v\n'", got, tt.wantDump) + } + } + { + // and at least a roundtip + reader := strings.NewReader(tt.wantStringXml) + readBuffer := utils.NewXmlReadBuffer(reader) + if got, err := model.TPKTPacketParse(readBuffer); err != nil || !reflect.DeepEqual(got, tt.args.debuggable) { + if err != nil { + t.Error(err) + } else { + t.Errorf("Roundtrip = '\n%v\n', want '\n%v\n'", got, tt.wantDump) + } } } }) diff --git a/plc4go/internal/plc4go/spi/utils/Buffer.go b/plc4go/internal/plc4go/spi/utils/Buffer.go new file mode 100644 index 0000000..99df612 --- /dev/null +++ b/plc4go/internal/plc4go/spi/utils/Buffer.go @@ -0,0 +1,85 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 utils + +// WithReaderWriterArgs is a marker interface for reader args supplied by the builders +type WithReaderWriterArgs interface { + WithReaderArgs + WithWriterArgs +} + +// WithAdditionalStringRepresentation can be used by e.g. enums to supply an additional string representation +func WithAdditionalStringRepresentation(stringRepresentation string) WithReaderWriterArgs { + return withAdditionalStringRepresentation{stringRepresentation: stringRepresentation} +} + +// WithRenderAsList indicates that an element can be rendered as list +func WithRenderAsList(renderAsList bool) WithReaderWriterArgs { + return withRenderAsList{renderAsList: renderAsList} +} + +/////////////////////////////////////// +/////////////////////////////////////// +// +// Internal section +// + +type readerWriterArg struct { +} + +func (_ readerWriterArg) isWriterArgs() bool { + return true +} + +func (_ readerWriterArg) isReaderArgs() bool { + return true +} + +type withAdditionalStringRepresentation struct { + readerWriterArg + stringRepresentation string +} + +type withRenderAsList struct { + readerWriterArg + renderAsList bool +} + +func upcastReaderArgs(args ...WithReaderArgs) []WithReaderWriterArgs { + result := make([]WithReaderWriterArgs, len(args)) + for i, arg := range args { + result[i] = arg.(WithReaderWriterArgs) + } + return result +} + +func upcastWriterArgs(args ...WithWriterArgs) []WithReaderWriterArgs { + result := make([]WithReaderWriterArgs, len(args)) + for i, arg := range args { + result[i] = arg.(WithReaderWriterArgs) + } + return result +} + +// +// Internal section +// +/////////////////////////////////////// +/////////////////////////////////////// diff --git a/plc4go/internal/plc4go/spi/utils/ReadBufferXmlBased.go b/plc4go/internal/plc4go/spi/utils/ReadBufferXmlBased.go index cb8434f..21e1729 100644 --- a/plc4go/internal/plc4go/spi/utils/ReadBufferXmlBased.go +++ b/plc4go/internal/plc4go/spi/utils/ReadBufferXmlBased.go @@ -29,8 +29,8 @@ import ( func NewXmlReadBuffer(reader io.Reader) ReadBuffer { return &xmlReadBuffer{ - xml.NewDecoder(reader), - 1, + Decoder: xml.NewDecoder(reader), + pos: 1, } } @@ -41,6 +41,7 @@ func NewXmlReadBuffer(reader io.Reader) ReadBuffer { // type xmlReadBuffer struct { + bufferCommons *xml.Decoder pos uint } @@ -73,7 +74,7 @@ func (x *xmlReadBuffer) PullContext(logicalName string, readerArgs ...WithReader func (x *xmlReadBuffer) ReadBit(logicalName string, readerArgs ...WithReaderArgs) (bool, error) { var value bool - err := x.decode(logicalName, "bit", 1, readerArgs, &value) + err := x.decode(logicalName, rwBitKey, 1, readerArgs, &value) if err != nil { return false, err } @@ -83,7 +84,7 @@ func (x *xmlReadBuffer) ReadBit(logicalName string, readerArgs ...WithReaderArgs func (x *xmlReadBuffer) ReadUint8(logicalName string, bitLength uint8, readerArgs ...WithReaderArgs) (uint8, error) { var value uint8 - err := x.decode(logicalName, "uint", bitLength, readerArgs, &value) + err := x.decode(logicalName, rwUintKey, bitLength, readerArgs, &value) if err != nil { return 0, err } @@ -93,7 +94,7 @@ func (x *xmlReadBuffer) ReadUint8(logicalName string, bitLength uint8, readerArg func (x *xmlReadBuffer) ReadUint16(logicalName string, bitLength uint8, readerArgs ...WithReaderArgs) (uint16, error) { var value uint16 - err := x.decode(logicalName, "uint", bitLength, readerArgs, &value) + err := x.decode(logicalName, rwUintKey, bitLength, readerArgs, &value) if err != nil { return 0, err } @@ -103,7 +104,7 @@ func (x *xmlReadBuffer) ReadUint16(logicalName string, bitLength uint8, readerAr func (x *xmlReadBuffer) ReadUint32(logicalName string, bitLength uint8, readerArgs ...WithReaderArgs) (uint32, error) { var value uint32 - err := x.decode(logicalName, "uint", bitLength, readerArgs, &value) + err := x.decode(logicalName, rwUintKey, bitLength, readerArgs, &value) if err != nil { return 0, err } @@ -113,7 +114,7 @@ func (x *xmlReadBuffer) ReadUint32(logicalName string, bitLength uint8, readerAr func (x *xmlReadBuffer) ReadUint64(logicalName string, bitLength uint8, readerArgs ...WithReaderArgs) (uint64, error) { var value uint64 - err := x.decode(logicalName, "uint", bitLength, readerArgs, &value) + err := x.decode(logicalName, rwUintKey, bitLength, readerArgs, &value) if err != nil { return 0, err } @@ -123,7 +124,7 @@ func (x *xmlReadBuffer) ReadUint64(logicalName string, bitLength uint8, readerAr func (x *xmlReadBuffer) ReadInt8(logicalName string, bitLength uint8, readerArgs ...WithReaderArgs) (int8, error) { var value int8 - err := x.decode(logicalName, "int", bitLength, readerArgs, &value) + err := x.decode(logicalName, rwIntKey, bitLength, readerArgs, &value) if err != nil { return 0, err } @@ -133,7 +134,7 @@ func (x *xmlReadBuffer) ReadInt8(logicalName string, bitLength uint8, readerArgs func (x *xmlReadBuffer) ReadInt16(logicalName string, bitLength uint8, readerArgs ...WithReaderArgs) (int16, error) { var value int16 - err := x.decode(logicalName, "int", bitLength, readerArgs, &value) + err := x.decode(logicalName, rwIntKey, bitLength, readerArgs, &value) if err != nil { return 0, err } @@ -143,7 +144,7 @@ func (x *xmlReadBuffer) ReadInt16(logicalName string, bitLength uint8, readerArg func (x *xmlReadBuffer) ReadInt32(logicalName string, bitLength uint8, readerArgs ...WithReaderArgs) (int32, error) { var value int32 - err := x.decode(logicalName, "int", bitLength, readerArgs, &value) + err := x.decode(logicalName, rwIntKey, bitLength, readerArgs, &value) if err != nil { return 0, err } @@ -153,7 +154,7 @@ func (x *xmlReadBuffer) ReadInt32(logicalName string, bitLength uint8, readerArg func (x *xmlReadBuffer) ReadInt64(logicalName string, bitLength uint8, readerArgs ...WithReaderArgs) (int64, error) { var value int64 - err := x.decode(logicalName, "int", bitLength, readerArgs, &value) + err := x.decode(logicalName, rwIntKey, bitLength, readerArgs, &value) if err != nil { return 0, err } @@ -164,7 +165,7 @@ func (x *xmlReadBuffer) ReadInt64(logicalName string, bitLength uint8, readerArg func (x *xmlReadBuffer) ReadBigInt(logicalName string, bitLength uint64, readerArgs ...WithReaderArgs) (*big.Int, error) { var value big.Int // TODO: bitLength is too short for a big int - err := x.decode(logicalName, "int", uint8(bitLength), readerArgs, &value) + err := x.decode(logicalName, rwIntKey, uint8(bitLength), readerArgs, &value) if err != nil { return nil, err } @@ -178,7 +179,7 @@ func (x *xmlReadBuffer) ReadFloat32(logicalName string, signed bool, exponentBit bitLength += 1 } var value float32 - err := x.decode(logicalName, "float", bitLength, readerArgs, &value) + err := x.decode(logicalName, rwFloatKey, bitLength, readerArgs, &value) if err != nil { return 0, err } @@ -192,7 +193,7 @@ func (x *xmlReadBuffer) ReadFloat64(logicalName string, signed bool, exponentBit bitLength += 1 } var value float64 - err := x.decode(logicalName, "float", bitLength, readerArgs, &value) + err := x.decode(logicalName, rwFloatKey, bitLength, readerArgs, &value) if err != nil { return 0, err } @@ -206,7 +207,7 @@ func (x *xmlReadBuffer) ReadBigFloat(logicalName string, signed bool, exponentBi bitLength += 1 } var value big.Float - err := x.decode(logicalName, "float", bitLength, readerArgs, &value) + err := x.decode(logicalName, rwFloatKey, bitLength, readerArgs, &value) if err != nil { return nil, err } @@ -217,7 +218,7 @@ func (x *xmlReadBuffer) ReadBigFloat(logicalName string, signed bool, exponentBi func (x *xmlReadBuffer) ReadString(logicalName string, bitLength uint32, readerArgs ...WithReaderArgs) (string, error) { var value string // TODO: bitlength too short - err := x.decode(logicalName, "string", uint8(bitLength), readerArgs, &value) + err := x.decode(logicalName, rwStringKey, uint8(bitLength), readerArgs, &value) if err != nil { return "", err } @@ -279,7 +280,7 @@ func (x *xmlReadBuffer) decode(logicalName string, dataType string, bitLength ui if err != nil { return err } - err = validateStartElement(startElement, logicalName, dataType, bitLength, readerArgs...) + err = x.validateStartElement(startElement, logicalName, dataType, bitLength, readerArgs...) if err != nil { return err } @@ -290,38 +291,38 @@ func (x *xmlReadBuffer) decode(logicalName string, dataType string, bitLength ui return nil } -func validateStartElement(startElement xml.StartElement, logicalName string, dataType string, bitLength uint8, readerArgs ...WithReaderArgs) error { - logicalName = sanitizeLogicalName(logicalName) +func (x *xmlReadBuffer) validateStartElement(startElement xml.StartElement, logicalName string, dataType string, bitLength uint8, readerArgs ...WithReaderArgs) error { + logicalName = x.sanitizeLogicalName(logicalName) if startElement.Name.Local != logicalName { return errors.Errorf("unexpected element '%s'. Expected '%s'", startElement.Name.Local, logicalName) - } else if err := validateAttr(startElement.Attr, dataType, bitLength, readerArgs...); err != nil { + } else if err := x.validateAttr(startElement.Attr, dataType, bitLength, readerArgs...); err != nil { return errors.Wrap(err, "Error validating Attributes") } return nil } -func validateAttr(attr []xml.Attr, dataType string, bitLength uint8, readerArgs ...WithReaderArgs) error { +func (x *xmlReadBuffer) validateAttr(attr []xml.Attr, dataType string, bitLength uint8, readerArgs ...WithReaderArgs) error { dataTypeValidated := false bitLengthValidate := false for _, attribute := range attr { switch attribute.Name.Local { - case "dataType": + case rwDataTypeKey: if attribute.Value != dataType { - return errors.Errorf("Unexpected dataType :%s. Want %s", attribute.Value, dataType) + return errors.Errorf("Unexpected %s :%s. Want %s", rwDataTypeKey, attribute.Value, dataType) } dataTypeValidated = true - case "bitLength": + case rwBitLengthKey: if attribute.Value != fmt.Sprintf("%d", bitLength) { - return errors.Errorf("Unexpected bitLength '%s'. Want '%d'", attribute.Value, bitLength) + return errors.Errorf("Unexpected %s '%s'. Want '%d'", rwBitLengthKey, attribute.Value, bitLength) } bitLengthValidate = true } } if !dataTypeValidated { - return errors.New("required attribute dataType missing") + return errors.Errorf("required attribute %s missing", rwDataTypeKey) } if !bitLengthValidate { - return errors.New("required attribute bitLength missing") + return errors.Errorf("required attribute %s missing", rwBitLengthKey) } return nil } diff --git a/plc4go/internal/plc4go/spi/utils/WriteBufferBoxBased.go b/plc4go/internal/plc4go/spi/utils/WriteBufferBoxBased.go index 34acf88..24b5e68 100644 --- a/plc4go/internal/plc4go/spi/utils/WriteBufferBoxBased.go +++ b/plc4go/internal/plc4go/spi/utils/WriteBufferBoxBased.go @@ -38,23 +38,14 @@ func NewBoxedWriteBuffer() WriteBufferBoxBased { } } -// WithAdditionalStringRepresentation can be used by e.g. enums to supply an additional string representation -func WithAdditionalStringRepresentation(stringRepresentation string) WithWriterArgs { - return withAdditionalStringRepresentation{stringRepresentation: stringRepresentation} -} - /////////////////////////////////////// /////////////////////////////////////// // // Internal section // -type withAdditionalStringRepresentation struct { - writerArg - stringRepresentation string -} - type boxedWriteBuffer struct { + bufferCommons *list.List desiredWidth int currentWidth int @@ -78,7 +69,7 @@ func (b *boxedWriteBuffer) PushContext(_ string, _ ...WithWriterArgs) error { } func (b *boxedWriteBuffer) WriteBit(logicalName string, value bool, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) asInt := 0 if value { asInt = 1 @@ -88,79 +79,79 @@ func (b *boxedWriteBuffer) WriteBit(logicalName string, value bool, writerArgs . } func (b *boxedWriteBuffer) WriteUint8(logicalName string, bitLength uint8, value uint8, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0)) return nil } func (b *boxedWriteBuffer) WriteUint16(logicalName string, bitLength uint8, value uint16, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0)) return nil } func (b *boxedWriteBuffer) WriteUint32(logicalName string, bitLength uint8, value uint32, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0)) return nil } func (b *boxedWriteBuffer) WriteUint64(logicalName string, bitLength uint8, value uint64, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0)) return nil } func (b *boxedWriteBuffer) WriteInt8(logicalName string, bitLength uint8, value int8, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0)) return nil } func (b *boxedWriteBuffer) WriteInt16(logicalName string, bitLength uint8, value int16, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0)) return nil } func (b *boxedWriteBuffer) WriteInt32(logicalName string, bitLength uint8, value int32, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0)) return nil } func (b *boxedWriteBuffer) WriteInt64(logicalName string, bitLength uint8, value int64, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0)) return nil } func (b *boxedWriteBuffer) WriteBigInt(logicalName string, bitLength uint8, value *big.Int, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %d%s", bitLength/4, value, value, additionalStringRepresentation), 0)) return nil } func (b *boxedWriteBuffer) WriteFloat32(logicalName string, bitLength uint8, value float32, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %f%s", bitLength/4, value, value, additionalStringRepresentation), 0)) return nil } func (b *boxedWriteBuffer) WriteFloat64(logicalName string, bitLength uint8, value float64, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %f%s", bitLength/4, value, value, additionalStringRepresentation), 0)) return nil } func (b *boxedWriteBuffer) WriteBigFloat(logicalName string, bitLength uint8, value *big.Float, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %f%s", bitLength/4, value, value, additionalStringRepresentation), 0)) return nil } func (b *boxedWriteBuffer) WriteString(logicalName string, bitLength uint8, _ string, value string, writerArgs ...WithWriterArgs) error { - additionalStringRepresentation := extractAdditionalStringRepresentation(writerArgs...) + additionalStringRepresentation := b.extractAdditionalStringRepresentation(upcastWriterArgs(writerArgs...)...) b.PushBack(BoxString(logicalName, fmt.Sprintf("%#0*x %s%s", bitLength/4, value, value, additionalStringRepresentation), 0)) return nil } @@ -187,16 +178,3 @@ findTheBox: b.PushBack(asciiBox) return nil } - -func extractAdditionalStringRepresentation(writerArgs ...WithWriterArgs) string { - for _, arg := range writerArgs { - if !arg.isWriterArgs() { - panic("not a writer arg") - } - switch arg.(type) { - case withAdditionalStringRepresentation: - return " " + arg.(withAdditionalStringRepresentation).stringRepresentation - } - } - return "" -} diff --git a/plc4go/internal/plc4go/spi/utils/WriteBufferJsonBased.go b/plc4go/internal/plc4go/spi/utils/WriteBufferJsonBased.go new file mode 100644 index 0000000..237b12c --- /dev/null +++ b/plc4go/internal/plc4go/spi/utils/WriteBufferJsonBased.go @@ -0,0 +1,232 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 utils + +import ( + "encoding/json" + "fmt" + "github.com/pkg/errors" + "math/big" + "strings" +) + +type WriteBufferJsonBased interface { + WriteBuffer + GetJsonString() (string, error) +} + +func NewJsonWriteBuffer() WriteBufferJsonBased { + var jsonString strings.Builder + encoder := json.NewEncoder(&jsonString) + encoder.SetIndent("", " ") + return &jsonWriteBuffer{ + jsonString: &jsonString, + Encoder: encoder, + } +} + +/////////////////////////////////////// +/////////////////////////////////////// +// +// Internal section +// + +type jsonWriteBuffer struct { + bufferCommons + stack + *json.Encoder + jsonString *strings.Builder + rootNode interface{} +} + +type elementContext struct { + logicalName string + properties map[string]interface{} +} + +type listContext struct { + logicalName string + list []interface{} +} + +// +// Internal section +// +/////////////////////////////////////// +/////////////////////////////////////// + +func (j *jsonWriteBuffer) PushContext(logicalName string, writerArgs ...WithWriterArgs) error { + renderedAsList := j.isToBeRenderedAsList(upcastWriterArgs(writerArgs...)...) + if renderedAsList { + j.Push(&listContext{logicalName, make([]interface{}, 0)}) + } else { + j.Push(&elementContext{logicalName, make(map[string]interface{})}) + } + return nil +} + +func (j *jsonWriteBuffer) WriteBit(logicalName string, value bool, writerArgs ...WithWriterArgs) error { + return j.encodeNode(logicalName, value, j.generateAttr(logicalName, rwBitKey, 1, writerArgs...)) +} + +func (j *jsonWriteBuffer) WriteUint8(logicalName string, bitLength uint8, value uint8, writerArgs ...WithWriterArgs) error { + return j.encodeNode(logicalName, value, j.generateAttr(logicalName, rwUintKey, bitLength, writerArgs...)) +} + +func (j *jsonWriteBuffer) WriteUint16(logicalName string, bitLength uint8, value uint16, writerArgs ...WithWriterArgs) error { + return j.encodeNode(logicalName, value, j.generateAttr(logicalName, rwUintKey, bitLength, writerArgs...)) +} + +func (j *jsonWriteBuffer) WriteUint32(logicalName string, bitLength uint8, value uint32, writerArgs ...WithWriterArgs) error { + return j.encodeNode(logicalName, value, j.generateAttr(logicalName, rwUintKey, bitLength, writerArgs...)) +} + +func (j *jsonWriteBuffer) WriteUint64(logicalName string, bitLength uint8, value uint64, writerArgs ...WithWriterArgs) error { + return j.encodeNode(logicalName, value, j.generateAttr(logicalName, rwUintKey, bitLength, writerArgs...)) +} + +func (j *jsonWriteBuffer) WriteInt8(logicalName string, bitLength uint8, value int8, writerArgs ...WithWriterArgs) error { + return j.encodeNode(logicalName, value, j.generateAttr(logicalName, rwIntKey, bitLength, writerArgs...)) +} + +func (j *jsonWriteBuffer) WriteInt16(logicalName string, bitLength uint8, value int16, writerArgs ...WithWriterArgs) error { + return j.encodeNode(logicalName, value, j.generateAttr(logicalName, rwIntKey, bitLength, writerArgs...)) +} + +func (j *jsonWriteBuffer) WriteInt32(logicalName string, bitLength uint8, value int32, writerArgs ...WithWriterArgs) error { + return j.encodeNode(logicalName, value, j.generateAttr(logicalName, rwIntKey, bitLength, writerArgs...)) +} + +func (j *jsonWriteBuffer) WriteInt64(logicalName string, bitLength uint8, value int64, writerArgs ...WithWriterArgs) error { + return j.encodeNode(logicalName, value, j.generateAttr(logicalName, rwIntKey, bitLength, writerArgs...)) +} + +func (j *jsonWriteBuffer) WriteBigInt(logicalName string, bitLength uint8, value *big.Int, writerArgs ...WithWriterArgs) error { + return j.encodeNode(logicalName, value, j.generateAttr(logicalName, rwIntKey, bitLength, writerArgs...)) +} + +func (j *jsonWriteBuffer) WriteFloat32(logicalName string, bitLength uint8, value float32, writerArgs ...WithWriterArgs) error { + return j.encodeNode(logicalName, value, j.generateAttr(logicalName, rwFloatKey, bitLength, writerArgs...)) +} + +func (j *jsonWriteBuffer) WriteFloat64(logicalName string, bitLength uint8, value float64, writerArgs ...WithWriterArgs) error { + return j.encodeNode(logicalName, value, j.generateAttr(logicalName, rwFloatKey, bitLength, writerArgs...)) +} + +func (j *jsonWriteBuffer) WriteBigFloat(logicalName string, bitLength uint8, value *big.Float, writerArgs ...WithWriterArgs) error { + return j.encodeNode(logicalName, value, j.generateAttr(logicalName, rwFloatKey, bitLength, writerArgs...)) +} + +func (j *jsonWriteBuffer) WriteString(logicalName string, bitLength uint8, encoding string, value string, writerArgs ...WithWriterArgs) error { + attr := j.generateAttr(logicalName, rwStringKey, bitLength, writerArgs...) + attr[fmt.Sprintf("__plc4x_%s", rwEncodingKey)] = encoding + return j.encodeNode(logicalName, value, attr) +} + +func (j *jsonWriteBuffer) PopContext(logicalName string, _ ...WithWriterArgs) error { + pop := j.Pop() + var poppedName string + var unwrapped interface{} + switch pop.(type) { + case *elementContext: + context := pop.(*elementContext) + poppedName = context.logicalName + unwrapped = context.properties + case *listContext: + context := pop.(*listContext) + poppedName = context.logicalName + unwrapped = context.list + default: + panic("broken context") + } + if poppedName != logicalName { + return errors.Errorf("unexpected closing context %s, expected %s", poppedName, logicalName) + } + if j.Empty() { + lastElement := make(map[string]interface{}) + lastElement[logicalName] = unwrapped + j.rootNode = lastElement + return nil + } + j.rootNode = j.Peek() + switch j.rootNode.(type) { + case *elementContext: + context := j.rootNode.(*elementContext) + context.properties[logicalName] = unwrapped + case *listContext: + context := j.rootNode.(*listContext) + wrappedWrap := make(map[string]interface{}) + wrappedWrap[logicalName] = unwrapped + context.list = append(context.list, wrappedWrap) + default: + panic("broken context") + } + return nil +} + +func (j *jsonWriteBuffer) GetJsonString() (string, error) { + if j.rootNode == nil { + return "", errors.New("No content available") + } + err := j.Encode(j.rootNode) + if err != nil { + return "", err + } + return j.jsonString.String(), nil +} + +func (j *jsonWriteBuffer) encodeNode(logicalName string, value interface{}, attr map[string]interface{}, _ ...WithWriterArgs) error { + logicalName = j.sanitizeLogicalName(logicalName) + peek := j.Peek() + switch peek.(type) { + case *elementContext: + context := peek.(*elementContext) + context.properties[logicalName] = value + for key, attrValue := range attr { + context.properties[key] = attrValue + } + return nil + case *listContext: + context := peek.(*listContext) + m := make(map[string]interface{}) + m[logicalName] = value + context.list = append(context.list, m) + return nil + default: + panic("broken context") + } +} + +func (j *jsonWriteBuffer) generateAttr(logicalName string, dataType string, bitLength uint8, writerArgs ...WithWriterArgs) map[string]interface{} { + logicalName = j.sanitizeLogicalName(logicalName) + attr := make(map[string]interface{}) + attr[fmt.Sprintf("%s__plc4x_%s", logicalName, rwDataTypeKey)] = dataType + attr[fmt.Sprintf("%s__plc4x_%s", logicalName, rwBitLengthKey)] = bitLength + for _, arg := range writerArgs { + if !arg.isWriterArgs() { + panic("not a writer arg") + } + switch arg.(type) { + case withAdditionalStringRepresentation: + attr[fmt.Sprintf("%s__plc4x_%s", logicalName, rwStringRepresentationKey)] = arg.(withAdditionalStringRepresentation).stringRepresentation + } + } + return attr +} diff --git a/plc4go/internal/plc4go/spi/utils/WriteBufferXmlBased.go b/plc4go/internal/plc4go/spi/utils/WriteBufferXmlBased.go index 7193c0f..8a0bbbd 100644 --- a/plc4go/internal/plc4go/spi/utils/WriteBufferXmlBased.go +++ b/plc4go/internal/plc4go/spi/utils/WriteBufferXmlBased.go @@ -20,7 +20,6 @@ package utils import ( - "bufio" "encoding/xml" "fmt" "math/big" @@ -34,7 +33,7 @@ type WriteBufferXmlBased interface { func NewXmlWriteBuffer() WriteBufferXmlBased { var xmlString strings.Builder - encoder := xml.NewEncoder(bufio.NewWriterSize(&xmlString, 1024*16)) + encoder := xml.NewEncoder(&xmlString) encoder.Indent("", " ") return &xmlWriteBuffer{ xmlString: &xmlString, @@ -49,6 +48,7 @@ func NewXmlWriteBuffer() WriteBufferXmlBased { // type xmlWriteBuffer struct { + bufferCommons xmlString *strings.Builder *xml.Encoder } @@ -61,114 +61,72 @@ type xmlWriteBuffer struct { func (x *xmlWriteBuffer) PushContext(logicalName string, _ ...WithWriterArgs) error { // Pre-emptive flush to avoid overflow when for a long time no context gets popped - if err := x.Encoder.Flush(); err != nil { + if err := x.Flush(); err != nil { return err } - return x.Encoder.EncodeToken(xml.StartElement{Name: xml.Name{Local: sanitizeLogicalName(logicalName)}}) + return x.EncodeToken(xml.StartElement{Name: xml.Name{Local: x.sanitizeLogicalName(logicalName)}}) } func (x *xmlWriteBuffer) WriteBit(logicalName string, value bool, writerArgs ...WithWriterArgs) error { - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: generateAttr("bit", 1, writerArgs...), - }) + return x.encodeElement(logicalName, value, x.generateAttr(rwBitKey, 1, writerArgs...), writerArgs...) } func (x *xmlWriteBuffer) WriteUint8(logicalName string, bitLength uint8, value uint8, writerArgs ...WithWriterArgs) error { - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: generateAttr("uint", bitLength, writerArgs...), - }) + return x.encodeElement(logicalName, value, x.generateAttr(rwUintKey, bitLength, writerArgs...), writerArgs...) } func (x *xmlWriteBuffer) WriteUint16(logicalName string, bitLength uint8, value uint16, writerArgs ...WithWriterArgs) error { - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: generateAttr("uint", bitLength, writerArgs...), - }) + return x.encodeElement(logicalName, value, x.generateAttr(rwUintKey, bitLength, writerArgs...), writerArgs...) } func (x *xmlWriteBuffer) WriteUint32(logicalName string, bitLength uint8, value uint32, writerArgs ...WithWriterArgs) error { - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: generateAttr("uint", bitLength, writerArgs...), - }) + return x.encodeElement(logicalName, value, x.generateAttr(rwUintKey, bitLength, writerArgs...), writerArgs...) } func (x *xmlWriteBuffer) WriteUint64(logicalName string, bitLength uint8, value uint64, writerArgs ...WithWriterArgs) error { - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: generateAttr("uint", bitLength, writerArgs...), - }) + return x.encodeElement(logicalName, value, x.generateAttr(rwUintKey, bitLength, writerArgs...), writerArgs...) } func (x *xmlWriteBuffer) WriteInt8(logicalName string, bitLength uint8, value int8, writerArgs ...WithWriterArgs) error { - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: generateAttr("int", bitLength, writerArgs...), - }) + return x.encodeElement(logicalName, value, x.generateAttr(rwIntKey, bitLength, writerArgs...), writerArgs...) } func (x *xmlWriteBuffer) WriteInt16(logicalName string, bitLength uint8, value int16, writerArgs ...WithWriterArgs) error { - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: generateAttr("int", bitLength, writerArgs...), - }) + return x.encodeElement(logicalName, value, x.generateAttr(rwIntKey, bitLength, writerArgs...), writerArgs...) } func (x *xmlWriteBuffer) WriteInt32(logicalName string, bitLength uint8, value int32, writerArgs ...WithWriterArgs) error { - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: generateAttr("int", bitLength, writerArgs...), - }) + return x.encodeElement(logicalName, value, x.generateAttr(rwIntKey, bitLength, writerArgs...), writerArgs...) } func (x *xmlWriteBuffer) WriteInt64(logicalName string, bitLength uint8, value int64, writerArgs ...WithWriterArgs) error { - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: generateAttr("int", bitLength, writerArgs...), - }) + return x.encodeElement(logicalName, value, x.generateAttr(rwIntKey, bitLength, writerArgs...), writerArgs...) } func (x *xmlWriteBuffer) WriteBigInt(logicalName string, bitLength uint8, value *big.Int, writerArgs ...WithWriterArgs) error { - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: generateAttr("int", bitLength, writerArgs...), - }) + return x.encodeElement(logicalName, value, x.generateAttr(rwIntKey, bitLength, writerArgs...), writerArgs...) } func (x *xmlWriteBuffer) WriteFloat32(logicalName string, bitLength uint8, value float32, writerArgs ...WithWriterArgs) error { - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: generateAttr("float", bitLength, writerArgs...), - }) + return x.encodeElement(logicalName, value, x.generateAttr(rwFloatKey, bitLength, writerArgs...), writerArgs...) } func (x *xmlWriteBuffer) WriteFloat64(logicalName string, bitLength uint8, value float64, writerArgs ...WithWriterArgs) error { - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: generateAttr("float", bitLength, writerArgs...), - }) + return x.encodeElement(logicalName, value, x.generateAttr(rwFloatKey, bitLength, writerArgs...), writerArgs...) } func (x *xmlWriteBuffer) WriteBigFloat(logicalName string, bitLength uint8, value *big.Float, writerArgs ...WithWriterArgs) error { - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: generateAttr("float", bitLength, writerArgs...), - }) + return x.encodeElement(logicalName, value, x.generateAttr(rwFloatKey, bitLength, writerArgs...), writerArgs...) } func (x *xmlWriteBuffer) WriteString(logicalName string, bitLength uint8, encoding string, value string, writerArgs ...WithWriterArgs) error { - attr := generateAttr("string", bitLength, writerArgs...) - attr = append(attr, xml.Attr{Name: xml.Name{Local: "encoding"}, Value: encoding}) - return x.EncodeElement(value, xml.StartElement{ - Name: xml.Name{Local: sanitizeLogicalName(logicalName)}, - Attr: attr, - }) + attr := x.generateAttr(rwStringKey, bitLength, writerArgs...) + attr = append(attr, xml.Attr{Name: xml.Name{Local: rwEncodingKey}, Value: encoding}) + return x.encodeElement(logicalName, value, attr, writerArgs...) } func (x *xmlWriteBuffer) PopContext(logicalName string, _ ...WithWriterArgs) error { - if err := x.Encoder.EncodeToken(xml.EndElement{Name: xml.Name{Local: sanitizeLogicalName(logicalName)}}); err != nil { + if err := x.Encoder.EncodeToken(xml.EndElement{Name: xml.Name{Local: x.sanitizeLogicalName(logicalName)}}); err != nil { return err } return x.Encoder.Flush() @@ -178,14 +136,21 @@ func (x *xmlWriteBuffer) GetXmlString() string { return x.xmlString.String() } -func generateAttr(dataType string, bitLength uint8, writerArgs ...WithWriterArgs) []xml.Attr { +func (x *xmlWriteBuffer) encodeElement(logicalName string, value interface{}, attr []xml.Attr, _ ...WithWriterArgs) error { + return x.EncodeElement(value, xml.StartElement{ + Name: xml.Name{Local: x.sanitizeLogicalName(logicalName)}, + Attr: attr, + }) +} + +func (x *xmlWriteBuffer) generateAttr(dataType string, bitLength uint8, writerArgs ...WithWriterArgs) []xml.Attr { attrs := make([]xml.Attr, 2) attrs[0] = xml.Attr{ - Name: xml.Name{Local: "dataType"}, + Name: xml.Name{Local: rwDataTypeKey}, Value: dataType, } attrs[1] = xml.Attr{ - Name: xml.Name{Local: "bitLength"}, + Name: xml.Name{Local: rwBitLengthKey}, Value: fmt.Sprintf("%d", bitLength), } for _, arg := range writerArgs { @@ -195,17 +160,10 @@ func generateAttr(dataType string, bitLength uint8, writerArgs ...WithWriterArgs switch arg.(type) { case withAdditionalStringRepresentation: attrs = append(attrs, xml.Attr{ - Name: xml.Name{Local: "stringRepresentation"}, + Name: xml.Name{Local: rwStringRepresentationKey}, Value: arg.(withAdditionalStringRepresentation).stringRepresentation, }) } } return attrs } - -func sanitizeLogicalName(logicalName string) string { - if logicalName == "" { - return "value" - } - return logicalName -} diff --git a/plc4go/internal/plc4go/spi/utils/bufferCommons.go b/plc4go/internal/plc4go/spi/utils/bufferCommons.go new file mode 100644 index 0000000..fcec099 --- /dev/null +++ b/plc4go/internal/plc4go/spi/utils/bufferCommons.go @@ -0,0 +1,103 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 utils + +import "container/list" + +const ( + rwDataTypeKey = "dataType" + rwBitLengthKey = "bitLength" + rwStringRepresentationKey = "stringRepresentation" + rwBitKey = "bit" + rwUintKey = "uint" + rwIntKey = "int" + rwFloatKey = "float" + rwStringKey = "string" + rwEncodingKey = "encoding" +) + +type bufferCommons struct { +} + +func (b bufferCommons) sanitizeLogicalName(logicalName string) string { + if logicalName == "" { + return "value" + } + return logicalName +} + +func (b bufferCommons) isToBeRenderedAsList(readerWriterArgs ...WithReaderWriterArgs) bool { + for _, arg := range readerWriterArgs { + if !arg.isWriterArgs() && !arg.isReaderArgs() { + panic("not a reader or writer arg") + } + switch arg.(type) { + case withRenderAsList: + return arg.(withRenderAsList).renderAsList + } + } + return false +} + +func (b bufferCommons) extractAdditionalStringRepresentation(readerWriterArgs ...WithReaderWriterArgs) string { + for _, arg := range readerWriterArgs { + if !arg.isWriterArgs() && !arg.isReaderArgs() { + panic("not a reader or writer arg") + } + switch arg.(type) { + case withAdditionalStringRepresentation: + return " " + arg.(withAdditionalStringRepresentation).stringRepresentation + } + } + return "" +} + +type stack struct { + list.List +} + +func (s *stack) Push(value interface{}) interface{} { + s.PushBack(value) + return value +} + +func (s *stack) Pop() interface{} { + if s.Len() <= 0 { + return nil + } + element := s.Back() + if element == nil { + return nil + } + s.Remove(element) + return element.Value +} + +func (s *stack) Peek() interface{} { + back := s.Back() + if back == nil { + return nil + } + return back.Value +} + +func (s stack) Empty() bool { + return s.Len() == 0 +}