blob: 6de1b2e2b25df37a2a9ee753f7b1428de56064a5 [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.Collections;
using Avro.Generic;
using Avro.IO;
namespace Avro.Specific
{
/// <summary>
/// PreresolvingDatumReader for reading data to ISpecificRecord classes.
/// </summary>
/// <see cref="PreresolvingDatumReader{T}">For more information about performance considerations for choosing this implementation</see>
public class SpecificDatumReader<T> : PreresolvingDatumReader<T>
{
/// <summary>
/// Initializes a new instance of the <see cref="SpecificDatumReader{T}"/> class.
/// </summary>
/// <param name="writerSchema">Schema that was used to write the data.</param>
/// <param name="readerSchema">Schema to use when reading the data.</param>
public SpecificDatumReader(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.Enumeration:
case Schema.Type.String:
case Schema.Type.Null:
return false;
}
return true;
}
/// <inheritdoc/>
protected override ArrayAccess GetArrayAccess(ArraySchema readerSchema)
{
return new SpecificArrayAccess(readerSchema);
}
/// <inheritdoc/>
protected override EnumAccess GetEnumAccess(EnumSchema readerSchema)
{
return new SpecificEnumAccess();
}
/// <inheritdoc/>
protected override MapAccess GetMapAccess(MapSchema readerSchema)
{
return new SpecificMapAccess(readerSchema);
}
/// <inheritdoc/>
protected override RecordAccess GetRecordAccess(RecordSchema readerSchema)
{
if (readerSchema.Name == null)
{
// ipc support
return new GenericDatumReader<T>.GenericRecordAccess(readerSchema);
}
return new SpecificRecordAccess(readerSchema);
}
/// <inheritdoc/>
protected override FixedAccess GetFixedAccess(FixedSchema readerSchema)
{
return new SpecificFixedAccess(readerSchema);
}
private class SpecificEnumAccess : EnumAccess
{
public object CreateEnum(object reuse, int ordinal)
{
return ordinal;
}
}
private class SpecificRecordAccess : RecordAccess
{
private string typeName;
public SpecificRecordAccess(RecordSchema readerSchema)
{
typeName = readerSchema.Fullname;
}
public object CreateRecord(object reuse)
{
return reuse ?? ObjectCreator.Instance.New(typeName, Schema.Type.Record);
}
public object GetField(object record, string fieldName, int fieldPos)
{
return ((ISpecificRecord)record).Get(fieldPos);
}
public void AddField(object record, string fieldName, int fieldPos, object fieldValue)
{
((ISpecificRecord)record).Put(fieldPos, fieldValue);
}
}
private class SpecificFixedAccess : FixedAccess
{
private string typeName;
public SpecificFixedAccess(FixedSchema readerSchema)
{
typeName = readerSchema.Fullname;
}
public object CreateFixed(object reuse)
{
return reuse ?? ObjectCreator.Instance.New(typeName, Schema.Type.Fixed);
}
public byte[] GetFixedBuffer(object rec)
{
return ((SpecificFixed) rec).Value;
}
}
private class SpecificArrayAccess : ArrayAccess
{
private string typeName;
public SpecificArrayAccess(ArraySchema readerSchema)
{
bool nEnum = false;
string type = Avro.CodeGen.getType(readerSchema, false, ref nEnum);
type = type.Remove(0, 6); // remove IList<
type = type.Remove(type.Length - 1); // remove >
typeName = type;
}
public object Create(object reuse)
{
IList array;
if( reuse != null )
{
array = reuse as IList;
if( array == null )
throw new AvroException( "array object does not implement non-generic IList" );
// retaining existing behavior where array contents aren't reused
// TODO: try to reuse contents?
array.Clear();
}
else
array = ObjectCreator.Instance.New(typeName, Schema.Type.Array) as IList;
return array;
}
public void EnsureSize(ref object array, int targetSize)
{
// no action needed
}
public void Resize(ref object array, int targetSize)
{
// no action needed
}
public void AddElements( object array, int elements, int index, ReadItem itemReader, Decoder decoder, bool reuse )
{
var list = (IList)array;
for (int i=0; i < elements; i++)
{
list.Add( itemReader( null, decoder ) );
}
}
}
private class SpecificMapAccess : MapAccess
{
private string typeName;
public SpecificMapAccess(MapSchema readerSchema)
{
bool nEnum = false;
string type = Avro.CodeGen.getType(readerSchema, false, ref nEnum);
type = type.Remove(0, 19); // remove IDictionary<string,
type = type.Remove(type.Length - 1); // remove >
typeName = type;
}
public object Create(object reuse)
{
IDictionary map;
if (reuse != null)
{
map = reuse as IDictionary;
if (map == null)
throw new AvroException("map object does not implement non-generic IList");
map.Clear();
}
else
map = ObjectCreator.Instance.New(typeName, Schema.Type.Map) as System.Collections.IDictionary;
return map;
}
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);
}
}
}
}
}