Skip to content

Commit

Permalink
@AutoCodec: allow CONSTRUCTOR strategy to be used with dependency ele…
Browse files Browse the repository at this point in the history
…ment.

It's very common for a child to need a dependency that the parent does not.
This eliminates the need for a `@AutoCodec.Dependency D unusedDependency'
constructor parameter.

* Adds a marshaller for HashCode.

PiperOrigin-RevId: 180989432
  • Loading branch information
aoeui authored and Copybara-Service committed Jan 6, 2018
1 parent 11389d5 commit 04e7fd8
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public static enum Strategy {
* com.google.devtools.build.lib.skyframe.serialization.InjectingObjectCodec#deserialize}.
*
* <p>A compiler error will result if more than one constructor parameter has the
* {@code @Dependency} annotation.
* {@code @Dependency} annotation or if the annotation itself has a dependency element.
*/
@Target(ElementType.PARAMETER)
public static @interface Dependency {}
Expand All @@ -106,8 +106,7 @@ public static enum Strategy {
* {@link com.google.devtools.build.lib.skyframe.serialization.ObjectCodec} with the dependency
* type parameter matching the returned type.
*
* <p>This is for use with {@code PUBLIC_FIELDS}, and {@code POLYMORPHIC} strategies. It is an
* error to use this with the {@code CONSTRUCTOR} strategy.
* <p>It is an error to use this in conjunction with {@code @AutoCodec.Dependency}.
*/
Class<?> dependency() default Void.class;
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
TypeSpec.Builder codecClassBuilder = null;
switch (annotation.strategy()) {
case CONSTRUCTOR:
if (dependencyType != null) {
throw new IllegalArgumentException(
encodedType.getQualifiedName()
+ " uses the CONSTRUCTOR strategy and has a non-Void dependency "
+ dependencyType.getQualifiedName());
}
codecClassBuilder = buildClassWithConstructorStrategy(encodedType);
codecClassBuilder = buildClassWithConstructorStrategy(encodedType, dependencyType);
break;
case PUBLIC_FIELDS:
codecClassBuilder = buildClassWithPublicFieldsStrategy(encodedType, dependencyType);
Expand Down Expand Up @@ -150,9 +144,20 @@ private TypeElement getDependencyType(AutoCodec annotation) {
}
}

private TypeSpec.Builder buildClassWithConstructorStrategy(TypeElement encodedType) {
private TypeSpec.Builder buildClassWithConstructorStrategy(
TypeElement encodedType, @Nullable TypeElement dependency) {
ExecutableElement constructor = selectConstructorForConstructorStrategy(encodedType);
PartitionedParameters parameters = isolateDependency(constructor);
if (dependency != null) {
if (parameters.dependency != null) {
throw new IllegalArgumentException(
encodedType.getQualifiedName()
+ " has both a @Dependency annotated constructor parameter "
+ "and a non-Void dependency element "
+ dependency.getQualifiedName());
}
parameters.dependency = dependency;
}

TypeSpec.Builder codecClassBuilder =
AutoCodecUtil.initializeCodecClassBuilder(encodedType, parameters.dependency);
Expand All @@ -174,11 +179,7 @@ private TypeSpec.Builder buildClassWithConstructorStrategy(TypeElement encodedTy
private static class PartitionedParameters {
/** Non-dependency parameters. */
List<VariableElement> fields;
/**
* Parameter having the {@link AutoCodec.Dependency} annotation.
*
* <p>Null if no such parameter exists.
*/
/** Dependency for this codec or null if no such dependency exists. */
@Nullable TypeElement dependency;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Maps;
import com.google.common.hash.HashCode;
import com.google.devtools.build.lib.skyframe.serialization.InjectingObjectCodec;
import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.Marshaller.Context;
Expand Down Expand Up @@ -421,6 +422,26 @@ public void addDeserializationCode(Context context) {
}
};

/** Since we cannot add a codec to {@link HashCode}, it needs to be supported natively. */
private final Marshaller hashCodeMarshaller =
new Marshaller() {
@Override
public boolean matches(DeclaredType type) {
return matchesType(type, HashCode.class);
}

@Override
public void addSerializationCode(Context context) {
context.builder.addStatement("codedOut.writeByteArrayNoTag($L.asBytes())", context.name);
}

@Override
public void addDeserializationCode(Context context) {
context.builder.addStatement(
"$L = $T.fromBytes(codedIn.readByteArray())", context.name, HashCode.class);
}
};

private final Marshaller protoMarshaller =
new Marshaller() {
@Override
Expand Down Expand Up @@ -484,6 +505,7 @@ public void addDeserializationCode(Context context) {
mapMarshaller,
multimapMarshaller,
patternMarshaller,
hashCodeMarshaller,
protoMarshaller,
codecMarshaller);

Expand Down

0 comments on commit 04e7fd8

Please sign in to comment.