blob: d2585a6c64cb8ef810bc4b1d7b121493cec863ef [file] [log] [blame]
// Copyright 2010 Google Inc.
//
// 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.
package com.google.gwtorm.nosql;
import com.google.gwtorm.protobuf.ProtobufCodec;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.WireFormat;
import java.io.EOFException;
import java.io.IOException;
/** Encodes a relation number in front of an object. */
public class RelationCodec<T> extends ProtobufCodec<T> {
/**
* Pop the field number from the stream and return it.
*
* @param in the stream to pop the field number from. The caller is responsible for making sure
* the underlying stream had a mark set for at least 8 bytes so the tag can be examined,
* reset, and later read again during mergeFrom or decode.
* @return the field number of the relation.
* @throws IOException the stream cannot be read.
*/
public static int peekId(CodedInputStream in) throws IOException {
return in.readTag() >>> 3;
}
private final int fieldId;
private final ProtobufCodec<T> objectCodec;
public RelationCodec(int fieldId, ProtobufCodec<T> objectCodec) {
this.fieldId = fieldId;
this.objectCodec = objectCodec;
}
@Override
public T newInstance() {
return objectCodec.newInstance();
}
@Override
public int sizeof(T obj) {
int sz = objectCodec.sizeof(obj);
return CodedOutputStream.computeTagSize(fieldId) //
+ CodedOutputStream.computeRawVarint32Size(sz) //
+ sz;
}
@Override
public void encode(T obj, CodedOutputStream out) throws IOException {
int sz = objectCodec.sizeof(obj);
out.writeTag(fieldId, WireFormat.FieldType.MESSAGE.getWireType());
out.writeRawVarint32(sz);
objectCodec.encode(obj, out);
}
@Override
public void mergeFrom(CodedInputStream in, T obj) throws IOException {
boolean found = false;
for (; ; ) {
int tag = in.readTag();
if (tag == 0) {
if (found) {
break;
} else {
// Reached EOF. But we require an object in our only field.
throw new EOFException("Expected field " + fieldId);
}
}
if ((tag >>> 3) == fieldId) {
if ((tag & 0x7) == WireFormat.FieldType.MESSAGE.getWireType()) {
int sz = in.readRawVarint32();
int oldLimit = in.pushLimit(sz);
objectCodec.mergeFrom(in, obj);
in.checkLastTagWas(0);
in.popLimit(oldLimit);
found = true;
} else {
throw new InvalidProtocolBufferException(
"Field " + fieldId + " should be length delimited (wire type 2)");
}
} else {
in.skipField(tag);
}
}
}
}