/**
* 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.
*/
using System;
using System.Collections.Generic;
using Avro.IO;
namespace Avro.Generic
{
/// PreresolvingDatumReader for reading data to GenericRecord classes or primitives.
/// For more information about performance considerations for choosing this implementation
public class GenericDatumReader : PreresolvingDatumReader
{
public GenericDatumReader(Schema writerSchema, Schema readerSchema) : base(writerSchema, readerSchema)
{
}
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;
}
protected override ArrayAccess GetArrayAccess(ArraySchema readerSchema)
{
return new GenericArrayAccess();
}
protected override EnumAccess GetEnumAccess(EnumSchema readerSchema)
{
return new GenericEnumAccess(readerSchema);
}
protected override MapAccess GetMapAccess(MapSchema readerSchema)
{
return new GenericMapAccess();
}
protected override RecordAccess GetRecordAccess(RecordSchema readerSchema)
{
return new GenericRecordAccess(readerSchema);
}
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)
{
var ge = (GenericEnum) reuse;
if (ge.Schema.Equals(this.schema))
{
ge.Value = this.schema[ordinal];
return ge;
}
}
return new GenericEnum(this.schema, this.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(fieldName, 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)
{
var result = (IDictionary)reuse;
result.Clear();
return result;
}
return new Dictionary();
}
public void AddElements(object mapObj, int elements, ReadItem itemReader, Decoder decoder, bool reuse)
{
var map = ((IDictionary)mapObj);
for (int i = 0; i < elements; i++)
{
var key = decoder.ReadString();
map[key] = itemReader(null, decoder);
}
}
}
}
}