You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by cu...@apache.org on 2011/03/31 23:16:49 UTC
svn commit: r1087439 [2/6] - in /avro/trunk: ./ lang/csharp/
lang/csharp/lib/ lang/csharp/lib/main/ lang/csharp/lib/test/
lang/csharp/src/ lang/csharp/src/apache/ lang/csharp/src/apache/codegen/
lang/csharp/src/apache/codegen/Properties/ lang/csharp/sr...
Added: avro/trunk/lang/csharp/src/apache/main/Generic/DatumReader.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/DatumReader.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/DatumReader.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/DatumReader.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,325 @@
+/**
+ * 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
+{
+ public interface DatumReader<T>
+ {
+ Schema ReaderSchema { get; }
+ Schema WriterSchema { get; }
+
+ /// <summary>
+ /// Read a datum. Traverse the schema, depth-first, reading all leaf values
+ /// in the schema into a datum that is returned. If the provided datum is
+ /// non-null it may be reused and returned.
+ /// </summary>
+ T Read(T reuse, Decoder decoder);
+ }
+
+ ///// <summary>
+ ///// Deserialize Avro-encoded data into a .net data structure.
+ ///// </summary>
+ //public class DatumReader
+ //{
+ // public Schema WriterSchema { get; private set; }
+ // public Schema ReaderSchema { get; private set; }
+
+ // /// <summary>
+ // /// As defined in the Avro specification, we call the schema encoded
+ // /// in the data the "writer's schema", and the schema expected by the
+ // /// reader the "reader's schema".
+ // /// </summary>
+ // /// <param name="writerSchema"></param>
+ // /// <param name="readerSchema"></param>
+ // public DatumReader(Schema writerSchema, Schema readerSchema)
+ // {
+ // if (null == writerSchema) throw new ArgumentNullException("writerSchema", "writerSchema cannot be null.");
+ // if (null == readerSchema) throw new ArgumentNullException("readerSchema", "readerSchema cannot be null.");
+
+ // this.WriterSchema = writerSchema;
+ // this.ReaderSchema = readerSchema;
+ // }
+
+
+ // static bool checkProps(Schema a, Schema b, params string[] props)
+ // {
+ // foreach (string prop in props)
+ // {
+ // if (!string.Equals(a[prop], b[prop]))
+ // return false;
+ // }
+
+ // return true;
+ // }
+ // //static bool CheckProps(Schema schema_one, Schema schema_two, IEnumerable<string> props)
+ // //{
+
+ // //}
+
+ // static bool matchSchemas(Schema writers_schema, Schema readers_schema)
+ // {
+ // string w_type = writers_schema.Type, r_type = readers_schema.Type;
+
+ // if (string.Equals(Schema.UNION, w_type) || string.Equals(Schema.UNION, r_type))
+ // return true;
+ // else if (PrimitiveSchema.PrimitiveKeyLookup.ContainsKey(w_type) && PrimitiveSchema.PrimitiveKeyLookup.ContainsKey(r_type) && w_type == r_type)
+ // return true;
+ // else if (w_type == Schema.RECORD && r_type == Schema.RECORD && DatumReader.checkProps(writers_schema, readers_schema, "fullname"))
+ // return true;
+ // else if (w_type == "error" && r_type == "error" && DatumReader.checkProps(writers_schema, readers_schema, "fullname"))
+ // return true;
+ // else if (w_type == "request" && r_type == "request")
+ // return true;
+ // else if (w_type == Schema.FIXED && r_type == Schema.FIXED && DatumReader.checkProps(writers_schema, readers_schema, "fullname", "size"))
+ // return true;
+ // else if (w_type == Schema.ENUM && r_type == Schema.ENUM && DatumReader.checkProps(writers_schema, readers_schema, "fullname"))
+ // return true;
+ // //else if (w_type == Schema.MAP && r_type == Schema.MAP && DatumReader.CheckProps(writers_schema.values, readers_schema.values, "type"))
+ // // return true;
+ // //else if (w_type == Schema.ARRAY && r_type == Schema.ARRAY && DatumReader.check_props(writers_schema.items, readers_schema.items, "type"))
+ // // return true;
+ // else if (w_type == Schema.INT && Util.checkIsValue(r_type, Schema.LONG, Schema.FLOAT, Schema.DOUBLE))
+ // return true;
+ // else if (w_type == Schema.LONG && Util.checkIsValue(r_type, Schema.FLOAT, Schema.DOUBLE))
+ // return true;
+ // else if (w_type == Schema.FLOAT && r_type == Schema.DOUBLE)
+ // return true;
+
+ // if (Util.checkIsValue(w_type, Schema.MAP, Schema.ARRAY))
+ // throw new NotImplementedException(w_type);
+
+ // return false;
+ // }
+
+ // public object Read(BinaryDecoder decoder)
+ // {
+ // if (null == this.ReaderSchema)
+ // this.ReaderSchema = this.WriterSchema;
+
+ // return ReadData(this.WriterSchema, this.ReaderSchema, decoder);
+
+ // }
+
+ // private object ReadData(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+ // {
+ // if (!matchSchemas(writers_schema, readers_schema))
+ // throw new SchemaResolutionException("Schemas do not match.", writers_schema, readers_schema);
+
+ // if (writers_schema.Type != Schema.UNION && readers_schema.Type == Schema.UNION)
+ // {
+ // foreach (Schema s in ((UnionSchema)readers_schema).Schemas)
+ // {
+ // if (DatumReader.matchSchemas(writers_schema, s))
+ // {
+ // return ReadData(writers_schema, s, decoder);
+ // }
+ // }
+
+ // throw new SchemaResolutionException("Schemas do not match.", writers_schema, readers_schema);
+ // }
+
+ // if (writers_schema.Type == Schema.NULL)
+ // return decoder.ReadNull();
+ // else if (writers_schema.Type == Schema.BOOLEAN)
+ // return decoder.ReadBool();
+ // else if (writers_schema.Type == Schema.STRING)
+ // return decoder.ReadUTF8();
+ // else if (writers_schema.Type == Schema.INT)
+ // return decoder.ReadInt();
+ // else if (writers_schema.Type == Schema.LONG)
+ // return decoder.ReadLong();
+ // else if (writers_schema.Type == Schema.FLOAT)
+ // return decoder.ReadFloat();
+ // else if (writers_schema.Type == Schema.DOUBLE)
+ // return decoder.ReadDouble();
+ // else if (writers_schema.Type == Schema.BYTES)
+ // return decoder.ReadBytes();
+ // else if (writers_schema.Type == Schema.FIXED)
+ // return ReadFixed(writers_schema, readers_schema, decoder);
+ // else if (writers_schema.Type == Schema.ENUM)
+ // return ReadEnum(writers_schema, readers_schema, decoder);
+ // else if (writers_schema.Type == Schema.ARRAY)
+ // return ReadArray(writers_schema, readers_schema, decoder);
+ // else if (writers_schema.Type == Schema.MAP)
+ // return ReadMap(writers_schema, readers_schema, decoder);
+ // else if (writers_schema.Type == Schema.UNION)
+ // return ReadUnion(writers_schema, readers_schema, decoder);
+ // else if (Util.checkIsValue(writers_schema.Type, Schema.RECORD, "error", "request"))
+ // return ReadRecord(writers_schema, readers_schema, decoder);
+ // else
+ // throw new AvroException("Cannot Read unknown type type) " + writers_schema.Type);
+ // }
+
+ // public void SkipData(Schema writers_schema, BinaryDecoder decoder)
+ // {
+ // if (writers_schema.Type == Schema.NULL)
+ // decoder.SkipNull();
+ // else if (writers_schema.Type == Schema.BOOLEAN)
+ // decoder.SkipBoolean();
+ // else if (writers_schema.Type == Schema.STRING)
+ // decoder.SkipUTF8();
+ // else if (writers_schema.Type == Schema.INT)
+ // decoder.SkipInt();
+ // else if (writers_schema.Type == Schema.LONG)
+ // decoder.SkipLong();
+ // else if (writers_schema.Type == Schema.FLOAT)
+ // decoder.SkipFloat();
+ // else if (writers_schema.Type == Schema.DOUBLE)
+ // decoder.SkipDouble();
+ // else if (writers_schema.Type == Schema.BYTES)
+ // decoder.ReadBytes();
+ // else if (writers_schema.Type == Schema.FIXED)
+ // SkipFixed(writers_schema as FixedSchema, decoder);
+ // else if (writers_schema.Type == Schema.ENUM)
+ // SkipEnum(writers_schema, decoder);
+ // else if (writers_schema.Type == Schema.ARRAY)
+ // SkipArray(writers_schema as ArraySchema, decoder);
+ // else if (writers_schema.Type == Schema.MAP)
+ // SkipMap(writers_schema as MapSchema, decoder);
+ // else if (writers_schema.Type == Schema.UNION)
+ // SkipUnion(writers_schema as UnionSchema, decoder);
+ // else if (Util.checkIsValue(writers_schema.Type, Schema.RECORD, "error", "request"))
+ // SkipRecord(writers_schema as RecordSchema, decoder);
+ // else
+ // throw new AvroException("Unknown type type: %s" + writers_schema.Type);
+
+ // }
+
+ // private void SkipRecord(RecordSchema writers_schema, BinaryDecoder decoder)
+ // {
+ // foreach (Field field in writers_schema.Fields)
+ // SkipData(field.Schema, decoder);
+ // }
+
+ // private void SkipUnion(UnionSchema writers_schema, BinaryDecoder decoder)
+ // {
+ // int index_of_schema = (int)decoder.ReadLong();
+ // SkipData(writers_schema.Schemas[index_of_schema], decoder);
+ // }
+
+ // private void SkipMap(MapSchema writers_schema, BinaryDecoder decoder)
+ // {
+ // long block_count = decoder.ReadLong();
+ // while (block_count != 0)
+ // {
+ // if (block_count < 0)
+ // {
+ // long block_size = decoder.ReadLong();
+ // decoder.skip(block_size);
+ // }
+ // else
+ // {
+ // for (int i = 0; i < block_count; i++)
+ // {
+ // decoder.SkipUTF8();
+ // SkipData(writers_schema.Values, decoder);
+ // block_count = decoder.ReadLong();
+ // }
+ // }
+ // }
+ // }
+
+ // private void SkipArray(ArraySchema writers_schema, BinaryDecoder decoder)
+ // {
+ // long block_count = decoder.ReadLong();
+ // while (block_count != 0)
+ // {
+ // if (block_count < 0)
+ // {
+ // long block_size = decoder.ReadLong();
+ // decoder.skip(block_size);
+ // }
+ // else
+ // {
+ // for (int i = 0; i < block_count; i++)
+ // {
+ // decoder.SkipUTF8();
+ // SkipData(writers_schema.Items, decoder);
+ // block_count = decoder.ReadLong();
+ // }
+ // }
+ // }
+ // }
+
+ // private void SkipEnum(Schema writers_schema, BinaryDecoder decoder)
+ // {
+ // decoder.SkipInt();
+ // }
+
+ // private void SkipFixed(FixedSchema writers_schema, BinaryDecoder decoder)
+ // {
+ // decoder.skip(writers_schema.Size);
+ // }
+
+ // /// <summary>
+ // /// A record is encoded by encoding the values of its fields
+ // /// in the order that they are declared. In other words, a record
+ // /// is encoded as just the concatenation of the encodings of its fields.
+ // /// Field values are encoded per their schema.
+
+ // /// Schema Resolution:
+ // /// * the ordering of fields may be different: fields are matched by name.
+ // /// * schemas for fields with the same name in both records are resolved
+ // /// recursively.
+ // /// * if the writer's record contains a field with a name not present in the
+ // /// reader's record, the writer's value for that field is ignored.
+ // /// * if the reader's record schema has a field that contains a default value,
+ // /// and writer's schema does not have a field with the same name, then the
+ // /// reader should use the default value from its field.
+ // /// * if the reader's record schema has a field with no default value, and
+ // /// writer's schema does not have a field with the same name, then the
+ // /// field's value is unset.
+ // /// </summary>
+ // /// <param name="writers_schema"></param>
+ // /// <param name="readers_schema"></param>
+ // /// <param name="decoder"></param>
+ // /// <returns></returns>
+ // private object ReadRecord(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+ // {
+ // throw new NotImplementedException();
+ // }
+
+ // private object ReadUnion(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+ // {
+ // throw new NotImplementedException();
+ // }
+
+ // private object ReadMap(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+ // {
+ // throw new NotImplementedException();
+ // }
+
+ // private object ReadArray(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+ // {
+ // throw new NotImplementedException();
+ // }
+
+ // private object ReadEnum(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+ // {
+ // throw new NotImplementedException();
+ // }
+
+ // private object ReadFixed(Schema writers_schema, Schema readers_schema, BinaryDecoder decoder)
+ // {
+ // throw new NotImplementedException();
+ // }
+ //}
+}
Added: avro/trunk/lang/csharp/src/apache/main/Generic/DatumWriter.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/DatumWriter.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/DatumWriter.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/DatumWriter.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,28 @@
+/**
+ * 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 Avro.IO;
+
+namespace Avro.Generic
+{
+ public interface DatumWriter<T>
+ {
+ Schema Schema { get; }
+ void Write(T datum, Encoder encoder);
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Generic/GenericEnum.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/GenericEnum.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/GenericEnum.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/GenericEnum.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,63 @@
+/**
+ * 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 System.Text;
+
+namespace Avro.Generic
+{
+ /// <summary>
+ /// The defualt class to hold values for enum schema in GenericReader and GenericWriter.
+ /// </summary>
+ public class GenericEnum
+ {
+ public EnumSchema Schema { get; private set; }
+ private string value;
+ public string Value {
+ get { return value; }
+ set
+ {
+ if (! Schema.Contains(value)) throw new AvroException("Unknown value for enum: " + value + "(" + Schema + ")");
+ this.value = value;
+ }
+ }
+
+ public GenericEnum(EnumSchema schema, string value)
+ {
+ this.Schema = schema;
+ this.Value = value;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == this) return true;
+ return (obj != null && obj is GenericEnum) ? Value.Equals((obj as GenericEnum).Value) : false;
+ }
+
+ public override int GetHashCode()
+ {
+ return 17 * Value.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return "Schema: " + Schema + ", value: " + Value;
+ }
+
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Generic/GenericFixed.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/GenericFixed.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/GenericFixed.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/GenericFixed.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,109 @@
+/**
+ * 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 System.Linq;
+using System.Text;
+
+namespace Avro.Generic
+{
+ /// <summary>
+ /// The default type used by GenericReader and GenericWriter for objects for FixedSchema
+ /// </summary>
+ public class GenericFixed
+ {
+ protected readonly byte[] value;
+ private FixedSchema schema;
+
+ public FixedSchema Schema
+ {
+ get
+ {
+ return schema;
+ }
+
+ set
+ {
+ if (!(value is FixedSchema))
+ throw new AvroException("Schema " + value.Name + " in set is not FixedSchema");
+
+ if ((value as FixedSchema).Size != this.value.Length)
+ throw new AvroException("Schema " + value.Name + " Size " + (value as FixedSchema).Size + "is not equal to bytes length " + this.value.Length);
+
+ schema = value;
+ }
+ }
+
+ public GenericFixed(FixedSchema schema)
+ {
+ value = new byte[schema.Size];
+ this.Schema = schema;
+ }
+
+ public GenericFixed(FixedSchema schema, byte[] value)
+ {
+ this.value = new byte[schema.Size];
+ this.Schema = schema;
+ Value = value;
+ }
+
+ protected GenericFixed(uint size)
+ {
+ this.value = new byte[size];
+ }
+
+ public byte[] Value
+ {
+ get { return this.value; }
+ set
+ {
+ if (value.Length == this.value.Length)
+ {
+ Array.Copy(value, this.value, value.Length);
+ return;
+ }
+ throw new AvroException("Invalid length for fixed: " + value.Length + ", (" + Schema + ")");
+ }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (this == obj) return true;
+ if (obj != null && obj is GenericFixed)
+ {
+ GenericFixed that = obj as GenericFixed;
+ if (that.Schema.Equals(this.Schema))
+ {
+ for (int i = 0; i < value.Length; i++) if (this.value[i] != that.value[i]) return false;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ int result = Schema.GetHashCode();
+ foreach (byte b in value)
+ {
+ result += 23 * b;
+ }
+ return result;
+ }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Generic/GenericReader.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/GenericReader.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/GenericReader.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/GenericReader.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,632 @@
+/**
+ * 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;
+using System.IO;
+
+namespace Avro.Generic
+{
+ public delegate T Reader<T>();
+
+ /// <summary>
+ /// A general purpose reader of data from avro streams. This can optionally resolve if the reader's and writer's
+ /// schemas are different. This class is a wrapper around DefaultReader and offers a little more type safety. The default reader
+ /// has the flexibility to return any type of object for each read call because the Read() method is generic. This
+ /// class on the other hand can only return a single type because the type is a parameter to the class. Any
+ /// user defined extension should, however, be done to DefaultReader. This class is sealed.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public sealed class GenericReader<T> : DatumReader<T>
+ {
+ private readonly DefaultReader reader;
+
+ /// <summary>
+ /// Constructs a generic reader for the given schemas using the DefaultReader. If the
+ /// reader's and writer's schemas are different this class performs the resolution.
+ /// </summary>
+ /// <param name="writerSchema">The schema used while generating the data</param>
+ /// <param name="readerSchema">The schema desired by the reader</param>
+ public GenericReader(Schema writerSchema, Schema readerSchema)
+ : this(new DefaultReader(writerSchema, readerSchema))
+ {
+ }
+
+ /// <summary>
+ /// Constructs a generic reader by directly using the given DefaultReader
+ /// </summary>
+ /// <param name="reader">The actual reader to use</param>
+ public GenericReader(DefaultReader reader)
+ {
+ this.reader = reader;
+ }
+
+ public Schema WriterSchema { get { return reader.WriterSchema; } }
+
+ public Schema ReaderSchema { get { return reader.ReaderSchema; } }
+
+ public T Read(T reuse, Decoder d)
+ {
+ return reader.Read(reuse, d);
+ }
+ }
+
+ /// <summary>
+ /// The default implementation for the generic reader. It constructs new .NET objects for avro objects on the
+ /// stream and returns the .NET object. Users can directly use this class or, if they want to customize the
+ /// object types for differnt Avro schema types, can derive from this class. There are enough hooks in this
+ /// class to allow customization.
+ /// </summary>
+ /// <remarks>
+ /// <list type="table">
+ /// <listheader><term>Avro Type</term><description>.NET Type</description></listheader>
+ /// <item><term>null</term><description>null reference</description></item>
+ /// </list>
+ /// </remarks>
+ public class DefaultReader
+ {
+ public Schema ReaderSchema { get; private set; }
+ public Schema WriterSchema { get; private set; }
+
+
+ /// <summary>
+ /// Constructs the default reader for the given schemas using the DefaultReader. If the
+ /// reader's and writer's schemas are different this class performs the resolution.
+ /// This default implemenation maps Avro types to .NET types as follows:
+ /// </summary>
+ /// <param name="writerSchema">The schema used while generating the data</param>
+ /// <param name="readerSchema">The schema desired by the reader</param>
+ public DefaultReader(Schema writerSchema, Schema readerSchema)
+ {
+ this.ReaderSchema = readerSchema;
+ this.WriterSchema = writerSchema;
+ }
+
+ /// <summary>
+ /// Reads an object off the stream.
+ /// </summary>
+ /// <typeparam name="T">The type of object to read. A single schema typically returns an object of a single .NET class.
+ /// The only exception is UnionSchema, which can return a object of different types based on the branch selected.
+ /// </typeparam>
+ /// <param name="reuse">If not null, the implemenation will try to use to return the object</param>
+ /// <param name="decoder">The decoder for deserialization</param>
+ /// <returns></returns>
+ public T Read<T>(T reuse, Decoder decoder)
+ {
+ if (!ReaderSchema.CanRead(WriterSchema))
+ throw new AvroException("Schema mismatch. Reader: " + ReaderSchema + ", writer: " + WriterSchema);
+
+ return (T)Read(reuse, WriterSchema, ReaderSchema, decoder);
+ }
+
+ public object Read(object reuse, Schema writerSchema, Schema readerSchema, Decoder d)
+ {
+ if (readerSchema.Tag == Schema.Type.Union && writerSchema.Tag != Schema.Type.Union)
+ {
+ readerSchema = findBranch(readerSchema as UnionSchema, writerSchema);
+ }
+ /*
+ if (!readerSchema.CanRead(writerSchema))
+ {
+ throw new AvroException("Schema mismatch. Reader: " + readerSchema + ", writer: " + writerSchema);
+ }
+ */
+ switch (writerSchema.Tag)
+ {
+ case Schema.Type.Null:
+ return ReadNull(readerSchema, d);
+ case Schema.Type.Boolean:
+ return Read<bool>(writerSchema.Tag, readerSchema, d.ReadBoolean);
+ case Schema.Type.Int:
+ {
+ int i = Read<int>(writerSchema.Tag, readerSchema, d.ReadInt);
+ switch (readerSchema.Tag)
+ {
+ case Schema.Type.Long:
+ return (long)i;
+ case Schema.Type.Float:
+ return (float)i;
+ case Schema.Type.Double:
+ return (double)i;
+ default:
+ return i;
+ }
+ }
+ case Schema.Type.Long:
+ {
+ long l = Read<long>(writerSchema.Tag, readerSchema, d.ReadLong);
+ switch (readerSchema.Tag)
+ {
+ case Schema.Type.Float:
+ return (float)l;
+ case Schema.Type.Double:
+ return (double)l;
+ default:
+ return l;
+ }
+ }
+ case Schema.Type.Float:
+ {
+ float f = Read<float>(writerSchema.Tag, readerSchema, d.ReadFloat);
+ switch (readerSchema.Tag)
+ {
+ case Schema.Type.Double:
+ return (double)f;
+ default:
+ return f;
+ }
+ }
+ case Schema.Type.Double:
+ return Read<double>(writerSchema.Tag, readerSchema, d.ReadDouble);
+ case Schema.Type.String:
+ return Read<string>(writerSchema.Tag, readerSchema, d.ReadString);
+ case Schema.Type.Bytes:
+ return Read<byte[]>(writerSchema.Tag, readerSchema, d.ReadBytes);
+ case Schema.Type.Record:
+ return ReadRecord(reuse, (RecordSchema)writerSchema, readerSchema, d);
+ case Schema.Type.Enumeration:
+ return ReadEnum(reuse, (EnumSchema)writerSchema, readerSchema, d);
+ case Schema.Type.Fixed:
+ return ReadFixed(reuse, (FixedSchema)writerSchema, readerSchema, d);
+ case Schema.Type.Array:
+ return ReadArray(reuse, (ArraySchema)writerSchema, readerSchema, d);
+ case Schema.Type.Map:
+ return ReadMap(reuse, (MapSchema)writerSchema, readerSchema, d);
+ case Schema.Type.Union:
+ return ReadUnion(reuse, (UnionSchema)writerSchema, readerSchema, d);
+ default:
+ throw new AvroException("Unknown schema type: " + writerSchema);
+ }
+ }
+
+ /// <summary>
+ /// Deserializes a null from the stream.
+ /// </summary>
+ /// <param name="readerSchema">Reader's schema, which should be a NullSchema</param>
+ /// <param name="d">The decoder for deserialization</param>
+ /// <returns></returns>
+ protected virtual object ReadNull(Schema readerSchema, Decoder d)
+ {
+ d.ReadNull();
+ return null;
+ }
+
+ /// <summary>
+ /// A generic function to read primitive types
+ /// </summary>
+ /// <typeparam name="S">The .NET type to read</typeparam>
+ /// <param name="tag">The Avro type tag for the object on the stream</param>
+ /// <param name="readerSchema">A schema compatible to the Avro type</param>
+ /// <param name="reader">A function that can read the avro type from the stream</param>
+ /// <returns>The primitive type just read</returns>
+ protected S Read<S>(Schema.Type tag, Schema readerSchema, Reader<S> reader)
+ {
+ return reader();
+ }
+
+ /// <summary>
+ /// Deserializes a record from the stream.
+ /// </summary>
+ /// <param name="reuse">If not null, a record object that could be reused for returning the result</param>
+ /// <param name="writerSchema">The writer's RecordSchema</param>
+ /// <param name="readerSchema">The reader's schema, must be RecordSchema too.</param>
+ /// <param name="dec">The decoder for deserialization</param>
+ /// <returns>The record object just read</returns>
+ protected virtual object ReadRecord(object reuse, RecordSchema writerSchema, Schema readerSchema, Decoder dec)
+ {
+ RecordSchema rs = (RecordSchema)readerSchema;
+
+ object rec = CreateRecord(reuse, rs);
+ foreach (Field wf in writerSchema)
+ {
+ try
+ {
+ Field rf;
+ if (rs.TryGetFieldAlias(wf.Name, out rf))
+ {
+ object obj = null;
+ TryGetField(rec, wf.Name, rf.Pos, out obj);
+ AddField(rec, wf.Name, rf.Pos, Read(obj, wf.Schema, rf.Schema, dec));
+ }
+ else
+ Skip(wf.Schema, dec);
+ }
+ catch (Exception ex)
+ {
+ throw new AvroException(ex.Message + " in field " + wf.Name);
+ }
+ }
+
+ var defaultStream = new MemoryStream();
+ var defaultEncoder = new BinaryEncoder(defaultStream);
+ var defaultDecoder = new BinaryDecoder(defaultStream);
+ foreach (Field rf in rs)
+ {
+ if (writerSchema.Contains(rf.Name)) continue;
+
+ defaultStream.Position = 0; // reset for writing
+ Resolver.EncodeDefaultValue(defaultEncoder, rf.Schema, rf.DefaultValue);
+ defaultStream.Flush();
+ defaultStream.Position = 0; // reset for reading
+
+ object obj = null;
+ TryGetField(rec, rf.Name, rf.Pos, out obj);
+ AddField(rec, rf.Name, rf.Pos, Read(obj, rf.Schema, rf.Schema, defaultDecoder));
+ }
+
+ return rec;
+ }
+
+ /// <summary>
+ /// Creates a new record object. Derived classes can override this to return an object of their choice.
+ /// </summary>
+ /// <param name="reuse">If appropriate, will reuse this object instead of constructing a new one</param>
+ /// <param name="readerSchema">The schema the reader is using</param>
+ /// <returns></returns>
+ protected virtual object CreateRecord(object reuse, RecordSchema readerSchema)
+ {
+ GenericRecord ru = (reuse == null || !(reuse is GenericRecord) || !(reuse as GenericRecord).Schema.Equals(readerSchema)) ?
+ new GenericRecord(readerSchema) :
+ reuse as GenericRecord;
+ return ru;
+ }
+
+ /// <summary>
+ /// Used by the default implementation of ReadRecord() to get the existing field of a record object. The derived
+ /// classes can override this to make their own interpretation of the record object.
+ /// </summary>
+ /// <param name="record">The record object to be probed into. This is guaranteed to be one that was returned
+ /// by a previous call to CreateRecord.</param>
+ /// <param name="fieldName">The name of the field to probe.</param>
+ /// <param name="value">The value of the field, if found. Null otherwise.</param>
+ /// <returns>True if and only if a field with the given name is found.</returns>
+ protected virtual bool TryGetField(object record, string fieldName, int fieldPos, out object value)
+ {
+ return (record as GenericRecord).TryGetValue(fieldName, out value);
+ }
+
+ /// <summary>
+ /// Used by the default implementation of ReadRecord() to add a field to a record object. The derived
+ /// classes can override this to suit their own implementation of the record object.
+ /// </summary>
+ /// <param name="record">The record object to be probed into. This is guaranteed to be one that was returned
+ /// by a previous call to CreateRecord.</param>
+ /// <param name="fieldName">The name of the field to probe.</param>
+ /// <param name="fieldValue">The value to be added for the field</param>
+ protected virtual void AddField(object record, string fieldName, int fieldPos, object fieldValue)
+ {
+ (record as GenericRecord).Add(fieldName, fieldValue);
+ }
+
+ /// <summary>
+ /// Deserializes a enum. Uses CreateEnum to construct the new enum object.
+ /// </summary>
+ /// <param name="reuse">If appropirate, uses this instead of creating a new enum object.</param>
+ /// <param name="writerSchema">The schema the writer used while writing the enum</param>
+ /// <param name="readerSchema">The schema the reader is using</param>
+ /// <param name="d">The decoder for deserialization.</param>
+ /// <returns>An enum object.</returns>
+ protected virtual object ReadEnum(object reuse, EnumSchema writerSchema, Schema readerSchema, Decoder d)
+ {
+ EnumSchema es = readerSchema as EnumSchema;
+ return CreateEnum(reuse, readerSchema as EnumSchema, writerSchema[d.ReadEnum()]);
+ }
+
+ /// <summary>
+ /// Used by the default implementation of ReadEnum to construct a new enum object.
+ /// </summary>
+ /// <param name="reuse">If appropriate, use this enum object instead of a new one.</param>
+ /// <param name="es">The enum schema used by the reader.</param>
+ /// <param name="symbol">The symbol that needs to be used.</param>
+ /// <returns>The default implemenation returns a GenericEnum.</returns>
+ protected virtual object CreateEnum(object reuse, EnumSchema es, string symbol)
+ {
+ if (reuse is GenericEnum)
+ {
+ GenericEnum ge = reuse as GenericEnum;
+ if (ge.Schema.Equals(es))
+ {
+ ge.Value = symbol;
+ return ge;
+ }
+ }
+ return new GenericEnum(es, symbol);
+ }
+
+ /// <summary>
+ /// Deserializes an array and returns an array object. It uses CreateArray() and works on it before returning it.
+ /// It also uses GetArraySize(), ResizeArray(), SetArrayElement() and GetArrayElement() methods. Derived classes can
+ /// override these methods to customize their behavior.
+ /// </summary>
+ /// <param name="reuse">If appropriate, uses this instead of creating a new array object.</param>
+ /// <param name="writerSchema">The schema used by the writer.</param>
+ /// <param name="readerSchema">The schema that the reader uses.</param>
+ /// <param name="d">The decoder for deserialization.</param>
+ /// <returns>The deserialized array object.</returns>
+ protected virtual object ReadArray(object reuse, ArraySchema writerSchema, Schema readerSchema, Decoder d)
+ {
+
+ ArraySchema rs = (ArraySchema)readerSchema;
+ object result = CreateArray(reuse, rs);
+ int i = 0;
+ for (int n = (int)d.ReadArrayStart(); n != 0; n = (int)d.ReadArrayNext())
+ {
+ if (GetArraySize(result) < (i + n)) ResizeArray(ref result, i + n);
+ for (int j = 0; j < n; j++, i++)
+ {
+ SetArrayElement(result, i, Read(GetArrayElement(result, i), writerSchema.ItemSchema, rs.ItemSchema, d));
+ }
+ }
+ if (GetArraySize(result) != i) ResizeArray(ref result, i);
+ return result;
+ }
+
+ /// <summary>
+ /// Creates a new array object. The initial size of the object could be anything. The users
+ /// should use GetArraySize() to determine the size. The default implementation creates an <c>object[]</c>.
+ /// </summary>
+ /// <param name="reuse">If appropriate use this instead of creating a new one.</param>
+ /// <returns>An object suitable to deserialize an avro array</returns>
+ protected virtual object CreateArray(object reuse, ArraySchema rs)
+ {
+ return (reuse != null && reuse is object[]) ? (object[])reuse : new object[0];
+ }
+
+ /// <summary>
+ /// Returns the size of the given array object.
+ /// </summary>
+ /// <param name="array">Array object whose size is required. This is guaranteed to be somthing returned by
+ /// a previous call to CreateArray().</param>
+ /// <returns>The size of the array</returns>
+ protected virtual int GetArraySize(object array)
+ {
+ return (array as object[]).Length;
+ }
+
+ /// <summary>
+ /// Resizes the array to the new value.
+ /// </summary>
+ /// <param name="array">Array object whose size is required. This is guaranteed to be somthing returned by
+ /// a previous call to CreateArray().</param>
+ /// <param name="n">The new size.</param>
+ protected virtual void ResizeArray(ref object array, int n)
+ {
+ object[] o = array as object[];
+ Array.Resize(ref o, n);
+ array = o;
+ }
+
+ /// <summary>
+ /// Assigns a new value to the object at the given index
+ /// </summary>
+ /// <param name="array">Array object whose size is required. This is guaranteed to be somthing returned by
+ /// a previous call to CreateArray().</param>
+ /// <param name="index">The index to reassign to.</param>
+ /// <param name="value">The value to assign.</param>
+ protected virtual void SetArrayElement(object array, int index, object value)
+ {
+ object[] a = array as object[];
+ a[index] = value;
+ }
+
+ /// <summary>
+ /// Returns the element at the given index.
+ /// </summary>
+ /// <param name="array">Array object whose size is required. This is guaranteed to be somthing returned by
+ /// a previous call to CreateArray().</param>
+ /// <param name="index">The index to look into.</param>
+ /// <returns>The object the given index. Null if no object has been assigned to that index.</returns>
+ protected virtual object GetArrayElement(object array, int index)
+ {
+ return (array as object[])[index];
+ }
+
+ /// <summary>
+ /// Deserialized an avro map. The default implemenation creats a new map using CreateMap() and then
+ /// adds elements to the map using AddMapEntry().
+ /// </summary>
+ /// <param name="reuse">If appropriate, use this instead of creating a new map object.</param>
+ /// <param name="writerSchema">The schema the writer used to write the map.</param>
+ /// <param name="readerSchema">The schema the reader is using.</param>
+ /// <param name="d">The decoder for serialization.</param>
+ /// <returns>The deserialized map object.</returns>
+ protected virtual object ReadMap(object reuse, MapSchema writerSchema, Schema readerSchema, Decoder d)
+ {
+ MapSchema rs = (MapSchema)readerSchema;
+ object result = CreateMap(reuse, rs);
+ for (int n = (int)d.ReadMapStart(); n != 0; n = (int)d.ReadMapNext())
+ {
+ for (int j = 0; j < n; j++)
+ {
+ string k = d.ReadString();
+ AddMapEntry(result, k, Read(null, writerSchema.ValueSchema, rs.ValueSchema, d));
+ }
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Used by the default implementation of ReadMap() to create a fresh map object. The default
+ /// implementaion of this method returns a IDictionary<string, map>.
+ /// </summary>
+ /// <param name="reuse">If appropriate, use this map object instead of creating a new one.</param>
+ /// <returns>An empty map object.</returns>
+ protected virtual object CreateMap(object reuse, MapSchema ms)
+ {
+ if (reuse != null && reuse is IDictionary<string, object>)
+ {
+ IDictionary<string, object> result = reuse as IDictionary<string, object>;
+ result.Clear();
+ return result;
+ }
+ return new Dictionary<string, object>();
+ }
+
+ /// <summary>
+ /// Adds an entry to the map.
+ /// </summary>
+ /// <param name="map">A map object, which is guaranteed to be one returned by a previous call to CreateMap().</param>
+ /// <param name="key">The key to add.</param>
+ /// <param name="value">The value to add.</param>
+ protected virtual void AddMapEntry(object map, string key, object value)
+ {
+ (map as IDictionary<string, object>).Add(key, value);
+ }
+
+ /// <summary>
+ /// Deserialized an object based on the writer's uninon schema.
+ /// </summary>
+ /// <param name="reuse">If appropriate, uses this object instead of creating a new one.</param>
+ /// <param name="writerSchema">The UnionSchema that the writer used.</param>
+ /// <param name="readerSchema">The schema the reader uses.</param>
+ /// <param name="d">The decoder for serialization.</param>
+ /// <returns>The deserialized object.</returns>
+ protected virtual object ReadUnion(object reuse, UnionSchema writerSchema, Schema readerSchema, Decoder d)
+ {
+ int index = d.ReadUnionIndex();
+ Schema ws = writerSchema[index];
+
+ if (readerSchema is UnionSchema)
+ readerSchema = findBranch(readerSchema as UnionSchema, ws);
+ else
+ if (!readerSchema.CanRead(ws))
+ throw new AvroException("Schema mismatch. Reader: " + ReaderSchema + ", writer: " + WriterSchema);
+
+ return Read(reuse, ws, readerSchema, d);
+ }
+
+ /// <summary>
+ /// Deserializes a fixed object and returns the object. The default implementation uses CreateFixed()
+ /// and GetFixedBuffer() and returns what CreateFixed() returned.
+ /// </summary>
+ /// <param name="reuse">If appropriate, uses this object instead of creating a new one.</param>
+ /// <param name="writerSchema">The FixedSchema the writer used during serialization.</param>
+ /// <param name="readerSchema">The schema that the readr uses. Must be a FixedSchema with the same
+ /// size as the writerSchema.</param>
+ /// <param name="d">The decoder for deserialization.</param>
+ /// <returns>The deserilized object.</returns>
+ protected virtual object ReadFixed(object reuse, FixedSchema writerSchema, Schema readerSchema, Decoder d)
+ {
+ FixedSchema rs = (FixedSchema)readerSchema;
+ if (rs.Size != writerSchema.Size)
+ {
+ throw new AvroException("Size mismatch between reader and writer fixed schemas. Writer: " + writerSchema +
+ ", reader: " + readerSchema);
+ }
+
+ object ru = CreateFixed(reuse, rs);
+ byte[] bb = GetFixedBuffer(ru);
+ d.ReadFixed(bb);
+ return ru;
+ }
+
+ /// <summary>
+ /// Returns a fixed object.
+ /// </summary>
+ /// <param name="reuse">If appropriate, uses this object instead of creating a new one.</param>
+ /// <param name="rs">The reader's FixedSchema.</param>
+ /// <returns>A fixed object with an appropriate buffer.</returns>
+ protected virtual object CreateFixed(object reuse, FixedSchema rs)
+ {
+ return (reuse != null && reuse is GenericFixed && (reuse as GenericFixed).Schema.Equals(rs)) ?
+ (GenericFixed)reuse : new GenericFixed(rs);
+ }
+
+ /// <summary>
+ /// Returns a buffer of appropriate size to read data into.
+ /// </summary>
+ /// <param name="f">The fixed object. It is guaranteed that this is something that has been previously
+ /// returned by CreateFixed</param>
+ /// <returns>A byte buffer of fixed's size.</returns>
+ protected virtual byte[] GetFixedBuffer(object f)
+ {
+ return (f as GenericFixed).Value;
+ }
+
+ protected virtual void Skip(Schema writerSchema, Decoder d)
+ {
+ switch (writerSchema.Tag)
+ {
+ case Schema.Type.Null:
+ d.SkipNull();
+ break;
+ case Schema.Type.Boolean:
+ d.SkipBoolean();
+ break;
+ case Schema.Type.Int:
+ d.SkipInt();
+ break;
+ case Schema.Type.Long:
+ d.SkipLong();
+ break;
+ case Schema.Type.Float:
+ d.SkipFloat();
+ break;
+ case Schema.Type.Double:
+ d.SkipDouble();
+ break;
+ case Schema.Type.String:
+ d.SkipString();
+ break;
+ case Schema.Type.Bytes:
+ d.SkipBytes();
+ break;
+ case Schema.Type.Record:
+ foreach (Field f in writerSchema as RecordSchema) Skip(f.Schema, d);
+ break;
+ case Schema.Type.Enumeration:
+ d.SkipEnum();
+ break;
+ case Schema.Type.Fixed:
+ d.SkipFixed((writerSchema as FixedSchema).Size);
+ break;
+ case Schema.Type.Array:
+ {
+ Schema s = (writerSchema as ArraySchema).ItemSchema;
+ for (long n = d.ReadArrayStart(); n != 0; n = d.ReadArrayNext())
+ {
+ for (long i = 0; i < n; i++) Skip(s, d);
+ }
+ }
+ break;
+ case Schema.Type.Map:
+ {
+ Schema s = (writerSchema as MapSchema).ValueSchema;
+ for (long n = d.ReadMapStart(); n != 0; n = d.ReadMapNext())
+ {
+ for (long i = 0; i < n; i++) { d.SkipString(); Skip(s, d); }
+ }
+ }
+ break;
+ case Schema.Type.Union:
+ Skip((writerSchema as UnionSchema)[d.ReadUnionIndex()], d);
+ break;
+ default:
+ throw new AvroException("Unknown schema type: " + writerSchema);
+ }
+ }
+
+ protected static Schema findBranch(UnionSchema us, Schema s)
+ {
+ int index = us.MatchingBranch(s);
+ if (index >= 0) return us[index];
+ throw new AvroException("No matching schema for " + s + " in " + us);
+ }
+
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Generic/GenericRecord.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/GenericRecord.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/GenericRecord.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/GenericRecord.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,137 @@
+/**
+ * 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 System.Linq;
+using System.Text;
+using Avro;
+
+namespace Avro.Generic
+{
+ /// <summary>
+ /// The default type used by GenericReader and GenericWriter for RecordSchema.
+ /// </summary>
+ public class GenericRecord
+ {
+ public RecordSchema Schema { get; private set; }
+
+ private IDictionary<string, object> contents = new Dictionary<string, object>();
+ public GenericRecord(RecordSchema schema)
+ {
+ this.Schema = schema;
+ }
+
+ public object this[string fieldName]
+ {
+ get { return contents[fieldName]; }
+ }
+
+ public void Add(string fieldName, object fieldValue)
+ {
+ if (Schema.Contains(fieldName))
+ {
+ // TODO: Use a matcher to verify that object has the right type for the field.
+ //contents.Add(fieldName, fieldValue);
+ contents[fieldName] = fieldValue;
+ return;
+ }
+ throw new AvroException("No such field: " + fieldName);
+ }
+
+ public bool TryGetValue(string fieldName, out object result)
+ {
+ return contents.TryGetValue(fieldName, out result);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (this == obj) return true;
+ if (obj != null && obj is GenericRecord)
+ {
+ GenericRecord other = obj as GenericRecord;
+ return Schema.Equals(other.Schema) && areEqual(contents, other.contents);
+ }
+ return false;
+ }
+
+ private static bool areEqual(IDictionary<string, object> d1, IDictionary<string, object> d2)
+ {
+ if (d1.Count == d2.Count)
+ {
+ foreach (KeyValuePair<string, object> kv in d1)
+ {
+ object o;
+ if (!d2.TryGetValue(kv.Key, out o)) return false;
+ if (!areEqual(o, kv.Value)) return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private static bool areEqual(object o1, object o2)
+ {
+ if (o1 == null) return o2 == null;
+ if (o2 == null) return false;
+ if (o1 is Array)
+ {
+ if (!(o2 is Array)) return false;
+ return areEqual(o1 as Array, o1 as Array);
+ }
+ else if (o1 is IDictionary<string, object>)
+ {
+ if (!(o2 is IDictionary<string, object>)) return false;
+ return areEqual(o1 as IDictionary<string, object>, o1 as IDictionary<string, object>);
+ }
+ return o1.Equals(o2);
+ }
+
+ private static bool areEqual(Array a1, Array a2)
+ {
+ if (a1.Length != a2.Length) return false;
+ for (int i = 0; i < a1.Length; i++)
+ {
+ if (!areEqual(a1.GetValue(i), a2.GetValue(i))) return false;
+ }
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ return 31 * contents.GetHashCode()/* + 29 * Schema.GetHashCode()*/;
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("Schema: ");
+ sb.Append(Schema);
+ sb.Append(", contents: ");
+ sb.Append("{ ");
+ foreach (KeyValuePair<string, object> kv in contents)
+ {
+ sb.Append(kv.Key);
+ sb.Append(": ");
+ sb.Append(kv.Value);
+ sb.Append(", ");
+ }
+ sb.Append("}");
+ return sb.ToString();
+ }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/Generic/GenericWriter.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/Generic/GenericWriter.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/Generic/GenericWriter.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/Generic/GenericWriter.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,445 @@
+/**
+ * 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
+{
+ public delegate void Writer<T>(T t);
+ /// <summary>
+ /// A typesafe wrapper around DefaultWriter. While a specific object of DefaultWriter
+ /// allows the client to serialize a generic type, an object of this class allows
+ /// only a single type of object to be serialized through it.
+ /// </summary>
+ /// <typeparam name="T">The type of object to be serialized.</typeparam>
+ public class GenericWriter<T> : DatumWriter<T>
+ {
+ private readonly DefaultWriter writer;
+ public GenericWriter(Schema schema) : this(new DefaultWriter(schema))
+ {
+
+ }
+
+ public Schema Schema { get { return writer.Schema; } }
+
+ public GenericWriter(DefaultWriter writer)
+ {
+ this.writer = writer;
+ }
+
+ /// <summary>
+ /// Serializes the given object using this writer's schema.
+ /// </summary>
+ /// <param name="value">The value to be serialized</param>
+ /// <param name="encoder">The encoder to use for serializing</param>
+ public void Write(T value, Encoder encoder)
+ {
+ writer.Write(value, encoder);
+ }
+ }
+
+ /// <summary>
+ /// A General purpose writer for serializing objects into a Stream using
+ /// Avro. This class implements a default way of serializing objects. But
+ /// one can derive a class from this and override different methods to
+ /// acheive results that are different from the default implementation.
+ /// </summary>
+ public class DefaultWriter
+ {
+ public Schema Schema { get; private set; }
+
+ /// <summary>
+ /// Constructs a generic writer for the given schema.
+ /// </summary>
+ /// <param name="schema">The schema for the object to be serialized</param>
+ public DefaultWriter(Schema schema)
+ {
+ this.Schema = schema;
+ }
+
+ public void Write<T>(T value, Encoder encoder)
+ {
+ Write(Schema, value, encoder);
+ }
+ /// <summary>
+ /// Examines the schema and dispatches the actual work to one
+ /// of the other methods of this class. This allows the derived
+ /// classes to override specific methods and get custom results.
+ /// </summary>
+ /// <param name="schema">The schema to use for serializing</param>
+ /// <param name="value">The value to be serialized</param>
+ /// <param name="encoder">The encoder to use during serialization</param>
+ public virtual void Write(Schema schema, object value, Encoder encoder)
+ {
+ switch (schema.Tag)
+ {
+ case Schema.Type.Null:
+ WriteNull(value, encoder);
+ break;
+ case Schema.Type.Boolean:
+ Write<bool>(value, schema.Tag, encoder.WriteBoolean);
+ break;
+ case Schema.Type.Int:
+ Write<int>(value, schema.Tag, encoder.WriteInt);
+ break;
+ case Schema.Type.Long:
+ Write<long>(value, schema.Tag, encoder.WriteLong);
+ break;
+ case Schema.Type.Float:
+ Write<float>(value, schema.Tag, encoder.WriteFloat);
+ break;
+ case Schema.Type.Double:
+ Write<double>(value, schema.Tag, encoder.WriteDouble);
+ break;
+ case Schema.Type.String:
+ Write<string>(value, schema.Tag, encoder.WriteString);
+ break;
+ case Schema.Type.Bytes:
+ Write<byte[]>(value, schema.Tag, encoder.WriteBytes);
+ break;
+ case Schema.Type.Record:
+ WriteRecord(schema as RecordSchema, value, encoder);
+ break;
+ case Schema.Type.Enumeration:
+ WriteEnum(schema as EnumSchema, value, encoder);
+ break;
+ case Schema.Type.Fixed:
+ WriteFixed(schema as FixedSchema, value, encoder);
+ break;
+ case Schema.Type.Array:
+ WriteArray(schema as ArraySchema, value, encoder);
+ break;
+ case Schema.Type.Map:
+ WriteMap(schema as MapSchema, value, encoder);
+ break;
+ case Schema.Type.Union:
+ WriteUnion(schema as UnionSchema, value, encoder);
+ break;
+ default:
+ error(schema, value);
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Serializes a "null"
+ /// </summary>
+ /// <param name="value">The object to be serialized using null schema</param>
+ /// <param name="encoder">The encoder to use while serialization</param>
+ protected virtual void WriteNull(object value, Encoder encoder)
+ {
+ if (value != null) throw TypeMismatch(value, "null", "null");
+ }
+
+ /// <summary>
+ /// A generic method to serialize primitive Avro types.
+ /// </summary>
+ /// <typeparam name="S">Type of the C# type to be serialized</typeparam>
+ /// <param name="value">The value to be serialized</param>
+ /// <param name="tag">The schema type tag</param>
+ /// <param name="writer">The writer which should be used to write the given type.</param>
+ protected virtual void Write<S>(object value, Schema.Type tag, Writer<S> writer)
+ {
+ if (!(value is S)) throw TypeMismatch(value, tag.ToString(), typeof(S).ToString());
+ writer((S)value);
+ }
+
+ /// <summary>
+ /// Serialized a record using the given RecordSchema. It uses GetField method
+ /// to extract the field value from the given object.
+ /// </summary>
+ /// <param name="schema">The RecordSchema to use for serialization</param>
+ /// <param name="value">The value to be serialized</param>
+ /// <param name="encoder">The Encoder for serialization</param>
+
+ protected virtual void WriteRecord(RecordSchema schema, object value, Encoder encoder)
+ {
+ EnsureRecordObject(schema, value);
+ foreach (Field field in schema)
+ {
+ try
+ {
+ object obj = GetField(value, field.Name, field.Pos);
+ Write(field.Schema, obj, encoder);
+ }
+ catch (Exception ex)
+ {
+ throw new AvroException(ex.Message + " in field " + field.Name);
+ }
+ }
+ }
+
+ protected virtual void EnsureRecordObject(RecordSchema s, object value)
+ {
+ if (value == null || !(value is GenericRecord) || !((value as GenericRecord).Schema.Equals(s)))
+ {
+ throw TypeMismatch(value, "record", "GenericRecord");
+ }
+ }
+
+ /// <summary>
+ /// Extracts the field value from the given object. In this default implementation,
+ /// value should be of type GenericRecord.
+ /// </summary>
+ /// <param name="value">The record value from which the field needs to be extracted</param>
+ /// <param name="fieldName">The name of the field in the record</param>
+ /// <param name="fieldPos">The position of field in the record</param>
+ /// <returns></returns>
+ protected virtual object GetField(object value, string fieldName, int fieldPos)
+ {
+ GenericRecord d = value as GenericRecord;
+ return d[fieldName];
+ }
+
+ /// <summary>
+ /// Serializes an enumeration. The default implementation expectes the value to be string whose
+ /// value is the name of the enumeration.
+ /// </summary>
+ /// <param name="es">The EnumSchema for serialization</param>
+ /// <param name="value">Value to be written</param>
+ /// <param name="encoder">Encoder for serialization</param>
+ protected virtual void WriteEnum(EnumSchema es, object value, Encoder encoder)
+ {
+ if (value == null || !(value is GenericEnum) || !((value as GenericEnum).Schema.Equals(es)))
+ throw TypeMismatch(value, "enum", "GenericEnum");
+ encoder.WriteEnum(es.Ordinal((value as GenericEnum).Value));
+ }
+
+ /// <summary>
+ /// Serialized an array. The default implementation calls EnsureArrayObject() to ascertain that the
+ /// given value is an array. It then calls GetArrayLength() and GetArrayElement()
+ /// to access the members of the array and then serialize them.
+ /// </summary>
+ /// <param name="schema">The ArraySchema for serialization</param>
+ /// <param name="value">The value being serialized</param>
+ /// <param name="encoder">The encoder for serialization</param>
+ protected virtual void WriteArray(ArraySchema schema, object value, Encoder encoder)
+ {
+ EnsureArrayObject(value);
+ long l = GetArrayLength(value);
+ encoder.WriteArrayStart();
+ encoder.SetItemCount(l);
+ for (long i = 0; i < l; i++)
+ {
+ encoder.StartItem();
+ Write(schema.ItemSchema, GetArrayElement(value, i), encoder);
+ }
+ encoder.WriteArrayEnd();
+ }
+
+ /// <summary>
+ /// Checks if the given object is an array. If it is a valid array, this function returns normally. Otherwise,
+ /// it throws an exception. The default implementation checks if the value is an array.
+ /// </summary>
+ /// <param name="value"></param>
+ protected virtual void EnsureArrayObject(object value)
+ {
+ if (value == null || !(value is Array)) throw TypeMismatch(value, "array", "Array");
+ }
+
+ /// <summary>
+ /// Returns the length of an array. The default implementation requires the object
+ /// to be an array of objects and returns its length. The defaul implementation
+ /// gurantees that EnsureArrayObject() has been called on the value before this
+ /// function is called.
+ /// </summary>
+ /// <param name="value">The object whose array length is required</param>
+ /// <returns>The array length of the given object</returns>
+ protected virtual long GetArrayLength(object value)
+ {
+ return (value as Array).Length;
+ }
+
+ /// <summary>
+ /// Returns the element at the given index from the given array object. The default implementation
+ /// requires that the value is an object array and returns the element in that array. The defaul implementation
+ /// gurantees that EnsureArrayObject() has been called on the value before this
+ /// function is called.
+ /// </summary>
+ /// <param name="value">The array object</param>
+ /// <param name="index">The index to look for</param>
+ /// <returns>The array element at the index</returns>
+ protected virtual object GetArrayElement(object value, long index)
+ {
+ return (value as Array).GetValue(index);
+ }
+
+ /// <summary>
+ /// Serialized a map. The default implementation first ensure that the value is indeed a map and then uses
+ /// GetMapSize() and GetMapElements() to access the contents of the map.
+ /// </summary>
+ /// <param name="schema">The MapSchema for serialization</param>
+ /// <param name="value">The value to be serialized</param>
+ /// <param name="encoder">The encoder for serialization</param>
+ protected virtual void WriteMap(MapSchema schema, object value, Encoder encoder)
+ {
+ EnsureMapObject(value);
+ IDictionary<string, object> vv = (IDictionary<string, object>)value;
+ encoder.WriteMapStart();
+ encoder.SetItemCount(GetMapSize(value));
+ foreach (KeyValuePair<string, object> obj in GetMapValues(vv))
+ {
+ encoder.StartItem();
+ encoder.WriteString(obj.Key);
+ Write(schema.ValueSchema, obj.Value, encoder);
+ }
+ encoder.WriteMapEnd();
+ }
+
+ /// <summary>
+ /// Checks if the given object is a map. If it is a valid map, this function returns normally. Otherwise,
+ /// it throws an exception. The default implementation checks if the value is an IDictionary<string, object>.
+ /// </summary>
+ /// <param name="value"></param>
+ protected virtual void EnsureMapObject(object value)
+ {
+ if (value == null || !(value is IDictionary<string, object>)) throw TypeMismatch(value, "map", "IDictionary<string, object>");
+ }
+
+ /// <summary>
+ /// Returns the size of the map object. The default implementation gurantees that EnsureMapObject has been
+ /// successfully called with the given value. The default implementation requires the value
+ /// to be an IDictionary<string, object> and returns the number of elements in it.
+ /// </summary>
+ /// <param name="value">The map object whose size is desired</param>
+ /// <returns>The size of the given map object</returns>
+ protected virtual long GetMapSize(object value)
+ {
+ return (value as IDictionary<string, object>).Count;
+ }
+
+ /// <summary>
+ /// Returns the contents of the given map object. The default implementation guarantees that EnsureMapObject
+ /// has been called with the given value. The defualt implementation of this method requires that
+ /// the value is an IDictionary<string, object> and returns its contents.
+ /// </summary>
+ /// <param name="value">The map object whose size is desired</param>
+ /// <returns>The contents of the given map object</returns>
+ protected virtual IEnumerable<KeyValuePair<string, object>> GetMapValues(object value)
+ {
+ return value as IDictionary<string, object>;
+ }
+
+ /// <summary>
+ /// Resolves the given value against the given UnionSchema and serializes the object against
+ /// the resolved schema member. The default implementation of this method uses
+ /// ResolveUnion to find the member schema within the UnionSchema.
+ /// </summary>
+ /// <param name="us">The UnionSchema to resolve against</param>
+ /// <param name="value">The value to be serialized</param>
+ /// <param name="encoder">The encoder for serialization</param>
+ protected virtual void WriteUnion(UnionSchema us, object value, Encoder encoder)
+ {
+ int index = ResolveUnion(us, value);
+ encoder.WriteUnionIndex(index);
+ Write(us[index], value, encoder);
+ }
+
+ /// <summary>
+ /// Finds the branch within the given UnionSchema that matches the given object. The default implementation
+ /// calls Matches() method in the order of branches within the UnionSchema. If nothing matches, throws
+ /// an exception.
+ /// </summary>
+ /// <param name="us">The UnionSchema to resolve against</param>
+ /// <param name="obj">The object that should be used in matching</param>
+ /// <returns></returns>
+ protected virtual int ResolveUnion(UnionSchema us, object obj)
+ {
+ for (int i = 0; i < us.Count; i++)
+ {
+ if (Matches(us[i], obj)) return i;
+ }
+ throw new AvroException("Cannot find a match for " + obj.GetType() + " in " + us);
+ }
+
+ /// <summary>
+ /// Serialized a fixed object. The default implementation requires that the value is
+ /// a GenericFixed object with an identical schema as es.
+ /// </summary>
+ /// <param name="es">The schema for serialization</param>
+ /// <param name="value">The value to be serialized</param>
+ /// <param name="encoder">The encoder for serialization</param>
+ protected virtual void WriteFixed(FixedSchema es, object value, Encoder encoder)
+ {
+ if (value == null || !(value is GenericFixed) || !(value as GenericFixed).Schema.Equals(es))
+ {
+ throw TypeMismatch(value, "fixed", "GenericFixed");
+ }
+ GenericFixed ba = (GenericFixed)value;
+ encoder.WriteFixed(ba.Value);
+ }
+
+ protected AvroException TypeMismatch(object obj, string schemaType, string type)
+ {
+ return new AvroException(type + " required to write against " + schemaType + " schema but found " + (null == obj ? "null" : obj.GetType().ToString()) );
+ }
+
+ private void error(Schema schema, Object value)
+ {
+ throw new AvroTypeException("Not a " + schema + ": " + value);
+ }
+
+ /*
+ * FIXME: This method of determining the Union branch has problems. If the data is IDictionary<string, object>
+ * if there are two branches one with record schema and the other with map, it choose the first one. Similarly if
+ * the data is byte[] and there are fixed and bytes schemas as branches, it choose the first one that matches.
+ * Also it does not recognize the arrays of primitive types.
+ */
+ protected virtual bool Matches(Schema sc, object obj)
+ {
+ if (obj == null && sc.Tag != Avro.Schema.Type.Null) return false;
+ switch (sc.Tag)
+ {
+ case Schema.Type.Null:
+ return obj == null;
+ case Schema.Type.Boolean:
+ return obj is bool;
+ case Schema.Type.Int:
+ return obj is int;
+ case Schema.Type.Long:
+ return obj is long;
+ case Schema.Type.Float:
+ return obj is float;
+ case Schema.Type.Double:
+ return obj is double;
+ case Schema.Type.Bytes:
+ return obj is byte[];
+ case Schema.Type.String:
+ return obj is string;
+ case Schema.Type.Record:
+ //return obj is GenericRecord && (obj as GenericRecord).Schema.Equals(s);
+ return obj is GenericRecord && (obj as GenericRecord).Schema.SchemaName.Equals((sc as RecordSchema).SchemaName);
+ case Schema.Type.Enumeration:
+ //return obj is GenericEnum && (obj as GenericEnum).Schema.Equals(s);
+ return obj is GenericEnum && (obj as GenericEnum).Schema.SchemaName.Equals((sc as EnumSchema).SchemaName);
+ case Schema.Type.Array:
+ return obj is Array && !(obj is byte[]);
+ case Schema.Type.Map:
+ return obj is IDictionary<string, object>;
+ case Schema.Type.Union:
+ return false; // Union directly within another union not allowed!
+ case Schema.Type.Fixed:
+ //return obj is GenericFixed && (obj as GenericFixed).Schema.Equals(s);
+ return obj is GenericFixed && (obj as GenericFixed).Schema.SchemaName.Equals((sc as FixedSchema).SchemaName);
+ default:
+ throw new AvroException("Unknown schema type: " + sc.Tag);
+ }
+ }
+ }
+}
Added: avro/trunk/lang/csharp/src/apache/main/IO/BinaryDecoder.cs
URL: http://svn.apache.org/viewvc/avro/trunk/lang/csharp/src/apache/main/IO/BinaryDecoder.cs?rev=1087439&view=auto
==============================================================================
--- avro/trunk/lang/csharp/src/apache/main/IO/BinaryDecoder.cs (added)
+++ avro/trunk/lang/csharp/src/apache/main/IO/BinaryDecoder.cs Thu Mar 31 21:16:28 2011
@@ -0,0 +1,299 @@
+/**
+ * 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 System.IO;
+
+namespace Avro.IO
+{
+ /// <summary>
+ /// Decoder for Avro binary format
+ /// </summary>
+ public class BinaryDecoder : Decoder
+ {
+ private readonly Stream stream;
+
+ public BinaryDecoder(Stream stream)
+ {
+ this.stream = stream;
+ }
+
+ /// <summary>
+ /// null is written as zero bytes
+ /// </summary>
+ public void ReadNull()
+ {
+ }
+
+ /// <summary>
+ /// a boolean is written as a single byte
+ /// whose value is either 0 (false) or 1 (true).
+ /// </summary>
+ /// <returns></returns>
+ public bool ReadBoolean()
+ {
+ byte b = read();
+ if (b == 0) return false;
+ if (b == 1) return true;
+ throw new AvroException("Not a boolean value in the stream: " + b);
+ }
+
+ /// <summary>
+ /// int and long values are written using variable-length, zig-zag coding.
+ /// </summary>
+ /// <param name="?"></param>
+ /// <returns></returns>
+ public int ReadInt()
+ {
+ return (int)ReadLong();
+ }
+ /// <summary>
+ /// int and long values are written using variable-length, zig-zag coding.
+ /// </summary>
+ /// <param name="?"></param>
+ /// <returns></returns>
+ public long ReadLong()
+ {
+ byte b = read();
+ ulong n = b & 0x7FUL;
+ int shift = 7;
+ while ((b & 0x80) != 0)
+ {
+ b = read();
+ n |= (b & 0x7FUL) << shift;
+ shift += 7;
+ }
+ long value = (long)n;
+ return (-(value & 0x01L)) ^ ((value >> 1) & 0x7fffffffffffffffL);
+ }
+
+ /// <summary>
+ /// A float is written as 4 bytes.
+ /// The float is converted into a 32-bit integer using a method equivalent to
+ /// Java's floatToIntBits and then encoded in little-endian format.
+ /// </summary>
+ /// <returns></returns>
+ public float ReadFloat()
+ {
+ byte[] buffer = read(4);
+
+ if (!BitConverter.IsLittleEndian)
+ Array.Reverse(buffer);
+
+ return BitConverter.ToSingle(buffer, 0);
+
+ //int bits = (Stream.ReadByte() & 0xff |
+ //(Stream.ReadByte()) & 0xff << 8 |
+ //(Stream.ReadByte()) & 0xff << 16 |
+ //(Stream.ReadByte()) & 0xff << 24);
+ //return intBitsToFloat(bits);
+ }
+
+ /// <summary>
+ /// A double is written as 8 bytes.
+ /// The double is converted into a 64-bit integer using a method equivalent to
+ /// Java's doubleToLongBits and then encoded in little-endian format.
+ /// </summary>
+ /// <param name="?"></param>
+ /// <returns></returns>
+ public double ReadDouble()
+ {
+ long bits = (stream.ReadByte() & 0xffL) |
+ (stream.ReadByte() & 0xffL) << 8 |
+ (stream.ReadByte() & 0xffL) << 16 |
+ (stream.ReadByte() & 0xffL) << 24 |
+ (stream.ReadByte() & 0xffL) << 32 |
+ (stream.ReadByte() & 0xffL) << 40 |
+ (stream.ReadByte() & 0xffL) << 48 |
+ (stream.ReadByte() & 0xffL) << 56;
+ return BitConverter.Int64BitsToDouble(bits);
+ }
+
+ /// <summary>
+ /// Bytes are encoded as a long followed by that many bytes of data.
+ /// </summary>
+ /// <returns></returns>
+ public byte[] ReadBytes()
+ {
+ return read(ReadLong());
+ }
+
+ public string ReadString()
+ {
+ int length = ReadInt();
+ byte[] buffer = new byte[length];
+ //TODO: Fix this because it's lame;
+ ReadFixed(buffer);
+ return System.Text.Encoding.UTF8.GetString(buffer);
+ }
+
+ public int ReadEnum()
+ {
+ return ReadInt();
+ }
+
+ public long ReadArrayStart()
+ {
+ return doReadItemCount();
+ }
+
+ public long ReadArrayNext()
+ {
+ return doReadItemCount();
+ }
+
+ public long ReadMapStart()
+ {
+ return doReadItemCount();
+ }
+
+ public long ReadMapNext()
+ {
+ return doReadItemCount();
+ }
+
+ public int ReadUnionIndex()
+ {
+ return ReadInt();
+ }
+
+ public void ReadFixed(byte[] buffer)
+ {
+ ReadFixed(buffer, 0, buffer.Length);
+ }
+
+ public void ReadFixed(byte[] buffer, int start, int length)
+ {
+ Read(buffer, start, length);
+ }
+
+ public void SkipNull()
+ {
+ ReadNull();
+ }
+
+ public void SkipBoolean()
+ {
+ ReadBoolean();
+ }
+
+
+ public void SkipInt()
+ {
+ ReadInt();
+ }
+
+ public void SkipLong()
+ {
+ ReadLong();
+ }
+
+ public void SkipFloat()
+ {
+ Skip(4);
+ }
+
+ public void SkipDouble()
+ {
+ Skip(8);
+ }
+
+ public void SkipBytes()
+ {
+ Skip(ReadLong());
+ }
+
+ public void SkipString()
+ {
+ SkipBytes();
+ }
+
+ public void SkipEnum()
+ {
+ ReadLong();
+ }
+
+ public void SkipUnionIndex()
+ {
+ ReadLong();
+ }
+
+ public void SkipFixed(int len)
+ {
+ Skip(len);
+ }
+
+ // Read p bytes into a new byte buffer
+ private byte[] read(long p)
+ {
+ byte[] buffer = new byte[p];
+ Read(buffer, 0, buffer.Length);
+ return buffer;
+ }
+
+ private static float intBitsToFloat(int value)
+ {
+ return BitConverter.ToSingle(BitConverter.GetBytes(value), 0);
+ }
+
+ private byte read()
+ {
+ int n = stream.ReadByte();
+ if (n >= 0) return (byte)n;
+ throw new AvroException("End of stream reached");
+ }
+
+ private void Read(byte[] buffer, int start, int len)
+ {
+ while (len > 0)
+ {
+ int n = stream.Read(buffer, start, len);
+ if (n <= 0) throw new AvroException("End of stream reached");
+ start += n;
+ len -= n;
+ }
+ }
+
+ private long doReadItemCount()
+ {
+ long result = ReadLong();
+ if (result < 0)
+ {
+ ReadLong(); // Consume byte-count if present
+ result = -result;
+ }
+ return result;
+ }
+
+ private void Skip(int p)
+ {
+ stream.Seek(p, SeekOrigin.Current);
+ }
+
+ private void Skip(long p)
+ {
+ stream.Seek(p, SeekOrigin.Current);
+ }
+
+ internal void skip(long block_size)
+ {
+ throw new NotImplementedException();
+ }
+
+ }
+}