blob: 965ba4f5cbbe3888d6ada073d278532fdb3850d0 [file] [log] [blame]
// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details.
// All rights reserved. Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
import 'package:meta/meta_meta.dart';
/// Implement this for a Built Value.
///
/// Then use built_value_generator.dart code generation functionality to
/// provide the rest of the implementation.
///
/// See https://github.com/google/built_value.dart/tree/master/example
abstract class Built<V extends Built<V, B>, B extends Builder<V, B>> {
/// Rebuilds the instance.
///
/// The result is the same as this instance but with [updates] applied.
/// [updates] is a function that takes a builder [B].
///
/// The implementation of this method will be generated for you by the
/// built_value generator.
V rebuild(Function(B) updates);
/// Converts the instance to a builder [B].
///
/// The implementation of this method will be generated for you by the
/// built_value generator.
B toBuilder();
}
/// Every [Built] class has a corresponding [Builder] class.
///
/// Usually you don't need to create one by hand; it will be generated
/// for you.
///
/// See <https://github.com/google/built_value.dart/tree/master/example>
abstract class Builder<V extends Built<V, B>, B extends Builder<V, B>> {
/// Replaces the value in the builder with a new one.
///
/// The implementation of this method will be generated for you by the
/// built_value generator.
void replace(V value);
/// Applies updates.
///
/// [updates] is a function that takes a builder [B].
void update(Function(B)? updates);
/// Builds.
///
/// The implementation of this method will be generated for you by the
/// built_value generator.
V build();
}
/// Optionally, annotate a Built Value with this to specify settings. This is
/// only needed for advanced use.
class BuiltValue {
/// Whether the Built Value is instantiable. Defaults to `true`.
///
/// A non-instantiable Built Value has no constructor or factory. No
/// implementation will be generated. But, an abstract builder will be
/// generated, or you may write one yourself.
///
/// Other Built Values may choose to `implement` a non-instantiable Built
/// Value, pulling in fields and methods from it. Their generated builders
/// will automatically `implement` the corresponding builder, so you can
/// access and modify the common inherited fields without knowing the
/// concrete type.
final bool instantiable;
/// Whether to use nested builders. Defaults to `true`.
///
/// If the builder class is fully generated, controls whether nested builders
/// are used. This means builder fields are themselves builders if there is a
/// builder available for each field type.
///
/// If you write the builder class by hand, this has no effect; simply
/// declare each field as the type you want, either the built type or the
/// builder.
final bool nestedBuilders;
/// Whether to auto create nested builders. Defaults to `true`.
///
/// When this is enabled, accessing a nested builder via a getter causes it
/// to be instantiated if it's `null`. In most cases this is convenient, but
/// if you are using builders for data processing then you might need to
/// check for `null`. If so you should set this to `false`.
final bool autoCreateNestedBuilders;
/// Whether builders should implement `operator==` and `hashCode`, making
/// them comparable.
///
/// May only be used with `nestedBuilders: false` and if the builder class
/// is fully generated.
final bool comparableBuilders;
/// Whether to generate an `onSet` field in the builder.
///
/// Defaults to `false`.
///
/// If generated the `onSet` field will have type `void Function()`, and will
/// be called after any setter is called. Assign your own function to
/// `onSet` to respond to changes to the builder.
final bool generateBuilderOnSetField;
/// The wire name when the class is serialized. Defaults to `null` which
/// indicates that the name is to be taken from the literal class name.
final String? wireName;
/// The default for [BuiltValueField.compare]. Set to `false` if you want to
/// ignore most fields when comparing, then mark the ones you do want to
/// compare on with `@BuiltValueField(compare: true)`.
final bool defaultCompare;
/// The default for [BuiltValueField.serialize]. Set to `false` if you want
/// to ignore most fields when serializing, then mark the ones you do want
/// to serialize with `@BuiltValueField(serialize: true)`.
final bool defaultSerialize;
const BuiltValue(
{this.instantiable = true,
this.nestedBuilders = true,
this.autoCreateNestedBuilders = true,
this.comparableBuilders = false,
this.generateBuilderOnSetField = false,
this.wireName,
this.defaultCompare = true,
this.defaultSerialize = true});
}
/// Nullable annotation for Built Value fields.
///
/// Fields marked with this annotation are allowed to be null.
const String nullable = 'nullable';
/// Optionally, annotate a Built Value field with this to specify settings.
/// This is only needed for advanced use.
@Target({TargetKind.getter})
class BuiltValueField {
/// Whether the field is compared and hashed. Defaults to `null` which means
/// [BuiltValue.defaultCompare] is used.
///
/// Set to `false` to ignore the field when calculating `hashCode` and when
/// comparing with `operator==`.
final bool? compare;
/// Whether the field is serialized. Defaults to `null` which means
/// [BuiltValue.defaultSerialize] is used.
///
/// If a field is not serialized, it must either be `@nullable` or specify a
/// default for deserialization to succeed.
final bool? serialize;
/// The wire name when the field is serialized. Defaults to `null` which
/// indicates the name is to be taken from the literal field name.
final String? wireName;
/// Whether the field overrides the `nestedBuilders` setting from the class. Defaults to `null` which
/// indicates the setting is to be taken from the `nestedBuilders` setting on the class.
final bool? nestedBuilder;
/// Whether the field overrides the `autoCreateNestedBuilders` setting from the class. Defaults to `null` which
/// indicates the setting is to be taken from the `autoCreateNestedBuilders` setting on the class.
final bool? autoCreateNestedBuilder;
const BuiltValueField(
{this.compare,
this.serialize,
this.wireName,
this.nestedBuilder,
this.autoCreateNestedBuilder});
}
/// Optionally, annotate a Built Value `Serializer` getters with this to
/// specify settings. This is only needed for advanced use.
@Target({TargetKind.getter})
class BuiltValueSerializer {
/// Set this to `true` to stop Built Value from generating a serializer for
/// you. The getter may then return any compatible `Serializer`. Defaults
/// to `false`.
final bool custom;
/// Whether the generated serializer should output `null`s.
///
/// By default this is `false` and nulls are omitted from the output.
final bool serializeNulls;
const BuiltValueSerializer(
{this.custom = false, this.serializeNulls = false});
}
/// Memoized annotation for Built Value getters.
///
/// Getters marked with this annotation are memoized: the result is calculated
/// once on first access and stored in the instance.
const String memoized = 'memoized';
/// Optionally, annotate an `EnumClass` with this to specify settings. This
/// is only needed for advanced use.
@Target({TargetKind.classType})
class BuiltValueEnum {
/// The wire name when the enum is serialized. Defaults to `null` which
/// indicates that the name is to be taken from the literal class name.
final String? wireName;
const BuiltValueEnum({this.wireName});
}
/// Optionally, annotate an `EnumClass` constant with this to specify settings.
/// This is only needed for advanced use.
@Target({TargetKind.field})
class BuiltValueEnumConst {
/// The wire name when the constant is serialized. Defaults to `null` which
/// indicates the name is to be taken from the literal field name.
///
/// Or, set [wireNumber] to serialize to an `int`. Only one of the two may be
/// used.
final String? wireName;
/// The wire name when the constant is serialized. Defaults to `null` which
/// indicates the name is to be taken from the literal field name.
///
/// Or, set [wireName] to serialize to a `String`. Only one of the two may
/// be used.
final int? wireNumber;
/// Marks a value that is used as a fallback when an unrecognized value
/// is encountered.
///
/// Defaults to `false`. At most one fallback is allowed per `EnumClass`.
///
/// Applies to the `valueOf` method and to deserialization; both will use
/// the fallback, if available, rather than throwing an exception.
final bool fallback;
const BuiltValueEnumConst(
{this.wireName, this.wireNumber, this.fallback = false});
}
/// Optionally, annotate methods with this to cause them to be called by
/// generated code.
@Target({TargetKind.method})
class BuiltValueHook {
/// Marks a static method that will be called when the builder for the
/// enclosing value type is initialized.
///
/// The method must accept a builder of the enclosing value type.
///
/// This example uses it to set a default value:
///
/// ```
/// @BuiltValueHook(initializeBuilder: true)
/// static void _initializeBuilder(MyClassBuilder b) =>
/// b..name = 'defaultName';
///
/// Defaults to `false`.
/// ```
final bool initializeBuilder;
/// Marks a static method that will be called immediately before the builder
/// for the enclosing value type is built.
///
/// The method must accept a builder of the enclosing value type.
///
/// This example uses it to make `items` sorted:
///
/// ```
/// @BuiltValueHook(initializeBuilder: true)
/// static void _finalizeBuilder(MyClassBuilder b) =>
/// b..items.sort();
///
/// Defaults to `false`.
/// ```
final bool finalizeBuilder;
const BuiltValueHook(
{this.initializeBuilder = false, this.finalizeBuilder = false});
}
/// Enum Class base class.
///
/// Extend this class then use the built_value.dart code generation
/// functionality to provide the rest of the implementation.
///
/// See https://github.com/google/built_value.dart/tree/master/example
class EnumClass {
final String name;
const EnumClass(this.name);
@override
String toString() => name;
}
/// For use by generated code in calculating hash codes. Do not use directly.
int $jc(int hash, int value) {
// Jenkins hash "combine".
hash = 0x1fffffff & (hash + value);
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
/// For use by generated code in calculating hash codes. Do not use directly.
int $jf(int hash) {
// Jenkins hash "finish".
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
/// Function that returns a [BuiltValueToStringHelper].
typedef BuiltValueToStringHelperProvider = BuiltValueToStringHelper Function(
String className);
/// Function used by generated code to get a [BuiltValueToStringHelper].
/// Set this to change built_value class toString() output. Built-in examples
/// are [IndentingBuiltValueToStringHelper], which is the default, and
/// [FlatBuiltValueToStringHelper].
BuiltValueToStringHelperProvider newBuiltValueToStringHelper =
(String className) => IndentingBuiltValueToStringHelper(className);
/// Interface for built_value toString() output helpers.
///
/// Note: this is an experimental feature. API may change without a major
/// version increase.
abstract class BuiltValueToStringHelper {
/// Add a field and its value.
void add(String field, Object? value);
/// Returns to completed toString(). The helper may not be used after this
/// method is called.
@override
String toString();
}
/// A [BuiltValueToStringHelper] that produces multi-line indented output.
class IndentingBuiltValueToStringHelper implements BuiltValueToStringHelper {
StringBuffer? _result = StringBuffer();
IndentingBuiltValueToStringHelper(String className) {
_result!..write(className)..write(' {\n');
_indentingBuiltValueToStringHelperIndent += 2;
}
@override
void add(String field, Object? value) {
if (value != null) {
_result!
..write(' ' * _indentingBuiltValueToStringHelperIndent)
..write(field)
..write('=')
..write(value)
..write(',\n');
}
}
@override
String toString() {
_indentingBuiltValueToStringHelperIndent -= 2;
_result!..write(' ' * _indentingBuiltValueToStringHelperIndent)..write('}');
var stringResult = _result.toString();
_result = null;
return stringResult;
}
}
int _indentingBuiltValueToStringHelperIndent = 0;
/// A [BuiltValueToStringHelper] that produces single line output.
class FlatBuiltValueToStringHelper implements BuiltValueToStringHelper {
StringBuffer? _result = StringBuffer();
bool _previousField = false;
FlatBuiltValueToStringHelper(String className) {
_result!..write(className)..write(' {');
}
@override
void add(String field, Object? value) {
if (value != null) {
if (_previousField) _result!.write(',');
_result!..write(field)..write('=')..write(value);
_previousField = true;
}
}
@override
String toString() {
_result!.write('}');
var stringResult = _result.toString();
_result = null;
return stringResult;
}
}
/// [Error] indicating that a built_value class constructor was called with
/// a `null` value for a field not marked `@nullable`.
class BuiltValueNullFieldError extends Error {
final String type;
final String field;
BuiltValueNullFieldError(this.type, this.field);
/// Throws a [BuiltValueNullFieldError] if [value] is `null`.
static T checkNotNull<T>(T? value, String type, String field) {
if (value == null) {
throw BuiltValueNullFieldError(type, field);
}
return value;
}
@override
String toString() =>
'Tried to construct class "$type" with null field "$field". '
'This is forbidden; to allow it, mark "$field" with @nullable.';
}
/// [Error] indicating that a built_value class constructor was called with
/// a missing or `dynamic` type parameter.
class BuiltValueMissingGenericsError extends Error {
final String type;
final String parameter;
BuiltValueMissingGenericsError(this.type, this.parameter);
@override
String toString() =>
'Tried to construct class "$type" with missing or dynamic '
'type argument "$parameter". All type arguments must be specified.';
}
/// [Error] indicating that a built_value `build` method failed because a
/// nested field builder failed.
class BuiltValueNestedFieldError extends Error {
final String type;
final String field;
final String error;
BuiltValueNestedFieldError(this.type, this.field, this.error);
@override
String toString() =>
'Tried to build class "$type" but nested builder for field "$field" '
'threw: $error';
}