// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.
// http://code.google.com/p/protobuf/
//
// Licensed 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;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers {
///
/// Implementation of the non-generic IMessage interface as far as possible.
///
public abstract class AbstractMessage : IMessage {
// TODO(jonskeet): Cleaner to use a Nullable?
///
/// The serialized size if it's already been computed, or -1
/// if we haven't computed it yet.
///
private int memoizedSize = -1;
#region Unimplemented members of IMessage
public abstract MessageDescriptor DescriptorForType { get; }
public abstract IDictionary AllFields { get; }
public abstract bool HasField(FieldDescriptor field);
public abstract object this[FieldDescriptor field] { get; }
public abstract int GetRepeatedFieldCount(FieldDescriptor field);
public abstract object this[FieldDescriptor field, int index] { get; }
public abstract UnknownFieldSet UnknownFields { get; }
#endregion
#region New abstract methods to be overridden by implementations, allow explicit interface implementation
protected abstract IMessage DefaultInstanceForTypeImpl { get; }
protected abstract IBuilder CreateBuilderForTypeImpl();
#endregion
#region Methods simply proxying to the "Impl" methods, explicitly implementing IMessage
IMessage IMessage.DefaultInstanceForType {
get { return DefaultInstanceForTypeImpl; }
}
IBuilder IMessage.CreateBuilderForType() {
return CreateBuilderForTypeImpl();
}
#endregion
public bool IsInitialized {
get {
// Check that all required fields are present.
foreach (FieldDescriptor field in DescriptorForType.Fields) {
if (field.IsRequired && !HasField(field)) {
return false;
}
}
// Check that embedded messages are initialized.
foreach (KeyValuePair entry in AllFields) {
FieldDescriptor field = entry.Key;
if (field.MappedType == MappedType.Message) {
if (field.IsRepeated) {
// We know it's an IList, but not the exact type - so
// IEnumerable is the best we can do. (C# generics aren't covariant yet.)
foreach (IMessage element in (IEnumerable)entry.Value) {
if (!element.IsInitialized) {
return false;
}
}
} else {
if (!((IMessage)entry.Value).IsInitialized) {
return false;
}
}
}
}
return true;
}
}
public sealed override string ToString() {
return TextFormat.PrintToString(this);
}
public void WriteTo(CodedOutputStream output) {
foreach (KeyValuePair entry in AllFields) {
FieldDescriptor field = entry.Key;
if (field.IsRepeated) {
// We know it's an IList, but not the exact type - so
// IEnumerable is the best we can do. (C# generics aren't covariant yet.)
foreach (object element in (IEnumerable)entry.Value) {
output.WriteField(field.FieldType, field.FieldNumber, element);
}
} else {
output.WriteField(field.FieldType, field.FieldNumber, entry.Value);
}
}
UnknownFieldSet unknownFields = UnknownFields;
if (DescriptorForType.Options.IsMessageSetWireFormat) {
unknownFields.WriteAsMessageSetTo(output);
} else {
unknownFields.WriteTo(output);
}
}
public int SerializedSize {
get {
int size = memoizedSize;
if (size != -1) {
return size;
}
size = 0;
foreach (KeyValuePair entry in AllFields) {
FieldDescriptor field = entry.Key;
if (field.IsRepeated) {
foreach (object element in (IEnumerable)entry.Value) {
size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
}
} else {
size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, entry.Value);
}
}
UnknownFieldSet unknownFields = UnknownFields;
if (DescriptorForType.Options.IsMessageSetWireFormat) {
size += unknownFields.SerializedSizeAsMessageSet;
} else {
size += unknownFields.SerializedSize;
}
memoizedSize = size;
return size;
}
}
public ByteString ToByteString() {
ByteString.CodedBuilder output = new ByteString.CodedBuilder(SerializedSize);
WriteTo(output.CodedOutput);
return output.Build();
}
public byte[] ToByteArray() {
byte[] result = new byte[SerializedSize];
CodedOutputStream output = CodedOutputStream.CreateInstance(result);
WriteTo(output);
output.CheckNoSpaceLeft();
return result;
}
public void WriteTo(Stream output) {
CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
WriteTo(codedOutput);
codedOutput.Flush();
}
public override bool Equals(object other) {
if (other == this) {
return true;
}
IMessage otherMessage = other as IMessage;
if (otherMessage == null || otherMessage.DescriptorForType != DescriptorForType) {
return false;
}
// TODO(jonskeet): Check that dictionaries support equality appropriately
// (I suspect they don't!)
return AllFields.Equals(otherMessage.AllFields);
}
public override int GetHashCode() {
int hash = 41;
hash = (19 * hash) + DescriptorForType.GetHashCode();
hash = (53 * hash) + AllFields.GetHashCode();
return hash;
}
#region IMessage Members
MessageDescriptor IMessage.DescriptorForType {
get { throw new NotImplementedException(); }
}
IDictionary IMessage.AllFields {
get { throw new NotImplementedException(); }
}
bool IMessage.HasField(FieldDescriptor field) {
throw new NotImplementedException();
}
object IMessage.this[FieldDescriptor field] {
get { throw new NotImplementedException(); }
}
int IMessage.GetRepeatedFieldCount(FieldDescriptor field) {
throw new NotImplementedException();
}
object IMessage.this[FieldDescriptor field, int index] {
get { throw new NotImplementedException(); }
}
UnknownFieldSet IMessage.UnknownFields {
get { throw new NotImplementedException(); }
}
bool IMessage.IsInitialized {
get { throw new NotImplementedException(); }
}
void IMessage.WriteTo(CodedOutputStream output) {
throw new NotImplementedException();
}
int IMessage.SerializedSize {
get { throw new NotImplementedException(); }
}
bool IMessage.Equals(object other) {
throw new NotImplementedException();
}
int IMessage.GetHashCode() {
throw new NotImplementedException();
}
string IMessage.ToString() {
throw new NotImplementedException();
}
ByteString IMessage.ToByteString() {
throw new NotImplementedException();
}
byte[] IMessage.ToByteArray() {
throw new NotImplementedException();
}
void IMessage.WriteTo(Stream output) {
throw new NotImplementedException();
}
#endregion
}
}