blob: 1ec126b3aa4a768ae510b06bded84efbee082da2 [file] [log] [blame]
/*
* 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
*
* https://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.
*/
using System;
using System.Collections.Generic;
using Avro.IO;
namespace Avro.Generic
{
/// <summary>
/// <see cref="PreresolvingDatumReader{T}"/> for reading data to <see cref="GenericRecord"/>
/// classes or primitives.
/// <see cref="PreresolvingDatumReader{T}">For more information about performance considerations
/// for choosing this implementation</see>.
/// </summary>
/// <typeparam name="T">Type to deserialize data into.</typeparam>
public class GenericDatumReader<T> : PreresolvingDatumReader<T>
{
/// <summary>
/// Initializes a new instance of the <see cref="GenericDatumReader{T}"/> class.
/// </summary>
/// <param name="writerSchema">Schema that was used to write the data.</param>
/// <param name="readerSchema">Schema to use to read the data.</param>
public GenericDatumReader(Schema writerSchema, Schema readerSchema) : base(writerSchema, readerSchema)
{
}
/// <inheritdoc/>
protected override bool IsReusable(Schema.Type tag)
{
switch (tag)
{
case Schema.Type.Double:
case Schema.Type.Boolean:
case Schema.Type.Int:
case Schema.Type.Long:
case Schema.Type.Float:
case Schema.Type.Bytes:
case Schema.Type.String:
case Schema.Type.Null:
return false;
}
return true;
}
/// <inheritdoc/>
protected override ArrayAccess GetArrayAccess(ArraySchema readerSchema)
{
return new GenericArrayAccess();
}
/// <inheritdoc/>
protected override EnumAccess GetEnumAccess(EnumSchema readerSchema)
{
return new GenericEnumAccess(readerSchema);
}
/// <inheritdoc/>
protected override MapAccess GetMapAccess(MapSchema readerSchema)
{
return new GenericMapAccess();
}
/// <inheritdoc/>
protected override RecordAccess GetRecordAccess(RecordSchema readerSchema)
{
return new GenericRecordAccess(readerSchema);
}
/// <inheritdoc/>
protected override FixedAccess GetFixedAccess(FixedSchema readerSchema)
{
return new GenericFixedAccess(readerSchema);
}
class GenericEnumAccess : EnumAccess
{
private EnumSchema schema;
public GenericEnumAccess(EnumSchema schema)
{
this.schema = schema;
}
public object CreateEnum(object reuse, int ordinal)
{
if (reuse is GenericEnum ge)
{
if (ge.Schema.Equals(schema))
{
ge.Value = schema[ordinal];
return ge;
}
}
return new GenericEnum(schema, schema[ordinal]);
}
}
internal class GenericRecordAccess : RecordAccess
{
private RecordSchema schema;
public GenericRecordAccess(RecordSchema schema)
{
this.schema = schema;
}
public object CreateRecord(object reuse)
{
GenericRecord ru = (reuse == null || !(reuse is GenericRecord) || !(reuse as GenericRecord).Schema.Equals(this.schema)) ?
new GenericRecord(this.schema) :
reuse as GenericRecord;
return ru;
}
public object GetField(object record, string fieldName, int fieldPos)
{
object result;
if(!((GenericRecord)record).TryGetValue(fieldPos, out result))
{
return null;
}
return result;
}
public void AddField(object record, string fieldName, int fieldPos, object fieldValue)
{
((GenericRecord)record).Add(fieldName, fieldValue);
}
}
class GenericFixedAccess : FixedAccess
{
private FixedSchema schema;
public GenericFixedAccess(FixedSchema schema)
{
this.schema = schema;
}
public object CreateFixed(object reuse)
{
return (reuse is GenericFixed && (reuse as GenericFixed).Schema.Equals(this.schema)) ?
reuse : new GenericFixed(this.schema);
}
public byte[] GetFixedBuffer( object f )
{
return ((GenericFixed)f).Value;
}
}
class GenericArrayAccess : ArrayAccess
{
public object Create(object reuse)
{
return (reuse is object[]) ? reuse : new object[0];
}
public void EnsureSize(ref object array, int targetSize)
{
if (((object[])array).Length < targetSize)
SizeTo(ref array, targetSize);
}
public void Resize(ref object array, int targetSize)
{
SizeTo(ref array, targetSize);
}
public void AddElements( object arrayObj, int elements, int index, ReadItem itemReader, Decoder decoder, bool reuse )
{
var array = (object[]) arrayObj;
for (int i = index; i < index + elements; i++)
{
array[i] = reuse ? itemReader(array[i], decoder) : itemReader(null, decoder);
}
}
private static void SizeTo(ref object array, int targetSize)
{
var o = (object[]) array;
Array.Resize(ref o, targetSize);
array = o;
}
}
class GenericMapAccess : MapAccess
{
public object Create(object reuse)
{
if (reuse is IDictionary<string, object> result)
{
result.Clear();
return result;
}
return new Dictionary<string, object>();
}
public void AddElements(object mapObj, int elements, ReadItem itemReader, Decoder decoder, bool reuse)
{
var map = (IDictionary<string, object>)mapObj;
for (int i = 0; i < elements; i++)
{
var key = decoder.ReadString();
map[key] = itemReader(null, decoder);
}
}
}
}
}