/*
* Copyright 2016-present Facebook, 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.facebook.buck.rules.keys;
import com.facebook.buck.io.ArchiveMemberPath;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.rules.BuildRuleType;
import com.facebook.buck.rules.BuildTargetSourcePath;
import com.facebook.buck.rules.ExplicitBuildTargetSourcePath;
import com.facebook.buck.rules.ForwardingBuildTargetSourcePath;
import com.facebook.buck.rules.RuleKey;
import com.facebook.buck.rules.SourceRoot;
import com.facebook.buck.util.sha1.Sha1HashCode;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hasher;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.regex.Pattern;
/** An implementation of {@link RuleKeyHasher} that wraps Guava's {@link Hasher}. */
public class GuavaRuleKeyHasher implements RuleKeyHasher<HashCode> {
private final Hasher hasher;
public GuavaRuleKeyHasher(Hasher hasher) {
this.hasher = hasher;
}
private GuavaRuleKeyHasher putBytes(byte type, byte[] bytes) {
hasher.putBytes(bytes);
hasher.putInt(bytes.length);
hasher.putByte(type);
return this;
}
private GuavaRuleKeyHasher putStringified(byte type, String val) {
return putBytes(type, val.getBytes(StandardCharsets.UTF_8));
}
private GuavaRuleKeyHasher putBuildTarget(byte type, BuildTarget target) {
return putStringified(type, target.getFullyQualifiedName());
}
@Override
public GuavaRuleKeyHasher putKey(String key) {
return this.putStringified(RuleKeyHasherTypes.KEY, key);
}
@Override
public GuavaRuleKeyHasher putNull() {
hasher.putByte(RuleKeyHasherTypes.NULL);
return this;
}
@Override
public GuavaRuleKeyHasher putBoolean(boolean val) {
hasher.putByte(val ? RuleKeyHasherTypes.TRUE : RuleKeyHasherTypes.FALSE);
return this;
}
@Override
public GuavaRuleKeyHasher putNumber(Number val) {
if (val instanceof Integer) { // most common, so test first
hasher.putInt((Integer) val);
hasher.putByte(RuleKeyHasherTypes.INTEGER);
} else if (val instanceof Long) {
hasher.putLong((Long) val);
hasher.putByte(RuleKeyHasherTypes.LONG);
} else if (val instanceof Short) {
hasher.putShort((Short) val);
hasher.putByte(RuleKeyHasherTypes.SHORT);
} else if (val instanceof Byte) {
hasher.putByte((Byte) val);
hasher.putByte(RuleKeyHasherTypes.BYTE);
} else if (val instanceof Float) {
hasher.putFloat((Float) val);
hasher.putByte(RuleKeyHasherTypes.FLOAT);
} else if (val instanceof Double) {
hasher.putDouble((Double) val);
hasher.putByte(RuleKeyHasherTypes.DOUBLE);
} else {
throw new UnsupportedOperationException(("Unsupported Number type: " + val.getClass()));
}
return this;
}
@Override
public GuavaRuleKeyHasher putString(String val) {
return this.putStringified(RuleKeyHasherTypes.STRING, val);
}
@Override
public GuavaRuleKeyHasher putBytes(byte[] bytes) {
return putBytes(RuleKeyHasherTypes.BYTE_ARRAY, bytes);
}
@Override
public GuavaRuleKeyHasher putPattern(Pattern pattern) {
return this.putStringified(RuleKeyHasherTypes.PATTERN, pattern.toString());
}
@Override
public GuavaRuleKeyHasher putSha1(Sha1HashCode sha1) {
sha1.update(hasher);
hasher.putByte(RuleKeyHasherTypes.SHA1);
return this;
}
@Override
public GuavaRuleKeyHasher putPath(Path path, HashCode hash) {
this.putStringified(RuleKeyHasherTypes.PATH, path.toString());
this.putBytes(RuleKeyHasherTypes.PATH, hash.asBytes());
return this;
}
@Override
public GuavaRuleKeyHasher putArchiveMemberPath(ArchiveMemberPath path, HashCode hash) {
this.putStringified(RuleKeyHasherTypes.ARCHIVE_MEMBER_PATH, path.toString());
this.putBytes(RuleKeyHasherTypes.ARCHIVE_MEMBER_PATH, hash.asBytes());
return this;
}
@Override
public GuavaRuleKeyHasher putNonHashingPath(String path) {
return this.putStringified(RuleKeyHasherTypes.NON_HASHING_PATH, path);
}
@Override
public GuavaRuleKeyHasher putSourceRoot(SourceRoot sourceRoot) {
return this.putStringified(RuleKeyHasherTypes.SOURCE_ROOT, sourceRoot.getName());
}
@Override
public GuavaRuleKeyHasher putRuleKey(RuleKey ruleKey) {
return this.putBytes(RuleKeyHasherTypes.RULE_KEY, ruleKey.getHashCode().asBytes());
}
@Override
public GuavaRuleKeyHasher putBuildRuleType(BuildRuleType buildRuleType) {
return this.putStringified(RuleKeyHasherTypes.RULE_TYPE, buildRuleType.toString());
}
@Override
public GuavaRuleKeyHasher putBuildTarget(BuildTarget buildTarget) {
return this.putStringified(RuleKeyHasherTypes.TARGET, buildTarget.getFullyQualifiedName());
}
@Override
public RuleKeyHasher<HashCode> putBuildTargetSourcePath(BuildTargetSourcePath targetSourcePath) {
this.putBuildTarget(RuleKeyHasherTypes.TARGET_SOURCE_PATH, targetSourcePath.getTarget());
if (targetSourcePath instanceof ExplicitBuildTargetSourcePath) {
this.putStringified(
RuleKeyHasherTypes.TARGET_SOURCE_PATH,
((ExplicitBuildTargetSourcePath) targetSourcePath).getResolvedPath().toString());
} else if (targetSourcePath instanceof ForwardingBuildTargetSourcePath) {
this.putStringified(
RuleKeyHasherTypes.TARGET_SOURCE_PATH,
((ForwardingBuildTargetSourcePath) targetSourcePath).getDelegate().toString());
}
return this;
}
@Override
public GuavaRuleKeyHasher putContainer(Container container, int length) {
hasher.putByte(RuleKeyHasherTypes.containerSubType(container));
hasher.putInt(length);
hasher.putByte(RuleKeyHasherTypes.CONTAINER);
return this;
}
@Override
public GuavaRuleKeyHasher putWrapper(Wrapper wrapper) {
hasher.putByte(RuleKeyHasherTypes.wrapperSubType(wrapper));
hasher.putByte(RuleKeyHasherTypes.WRAPPER);
return this;
}
@Override
public HashCode hash() {
return hasher.hash();
}
}