load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load(
    "//features:global_features.bzl",
    "SUPPORTED_FEATURES",
)
load(
    ":crubit_feature_hint.bzl",
    "crubit_feature_hint",
)

package(
    default_applicable_licenses = ["//:license"],
    default_visibility = ["//visibility:private"],
)

_EXPERIMENTAL_CLIENTS = [
    "//:__subpackages__",
]

# A feature set containing all supported Crubit features.
# Add this to the `aspect_hints` of a `cc_library` to generate Rust bindings for that library.
#
# See crubit.rs-features#supported
crubit_feature_hint(
    name = "supported",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES,
    visibility = ["//visibility:public"],
)

_WRAPPER_FEATURES = [
    "wrapper",
]

# A feature set containing wrapper-library Crubit features, in addition to the officially supported
# features.
#
# NOTE: New usage of wrapper mode is discouraged.
#
# See crubit.rs-features#wrapper
crubit_feature_hint(
    name = "wrapper",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + _WRAPPER_FEATURES,
    visibility = _EXPERIMENTAL_CLIENTS,
)

# A feature set enabling forward declaration support.
crubit_feature_hint(
    name = "forward_declare",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["forward_declare"],
    visibility = _EXPERIMENTAL_CLIENTS,
)

# A rust_api_from_cpp feature which only enables bindings for types.
#
# If `types` is enabled, but `supported` is not, then named functions and methods will not receive
# bindings. However, constructors, destructors, and operators will still receive bindings, as these
# are essential for working with values of the provided type.
crubit_feature_hint(
    name = "types",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = ["types"],
    visibility = ["//visibility:public"],
)

# Explicitly disables assume_lifetimes for a target.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "no_assume_lifetimes",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["no_assume_lifetimes"],
    visibility = ["//visibility:public"],
)

# A feature set enabling ergonomic lifetime defaults when interpreting lifetime annotations.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "assume_lifetimes",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["assume_lifetimes"],
    visibility = ["//visibility:public"],
)

# A feature set containing experimental Crubit features, in addition to the officially supported
# features.
#
# See crubit.rs-features#experimental
crubit_feature_hint(
    name = "experimental",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = ["all"],
    visibility = _EXPERIMENTAL_CLIENTS,
)

# A feature set enabling the `this` pointer to be interpreted as a reference.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "assume_this_lifetimes",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["assume_this_lifetimes"],
    visibility = ["//visibility:public"],
)

# A feature set marking C++ classes with `[[gsl::Pointer]]` as unsafe.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "unsafe_view",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["unsafe_view"],
    visibility = ["//visibility:public"],
)

# A feature set where  C++ default constructors are checked to fully initialize all public fields.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "check_default_initialized",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["check_default_initialized"],
    visibility = ["//visibility:public"],
)

# A feature set enabling leading colons for C++ type paths in annotations.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "leading_colons_for_cpp_type",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["leading_colons_for_cpp_type"],
    visibility = ["//visibility:public"],
)

# A feature set enabling bindings for arbitrary template instantiations.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "template_instantiation",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["template_instantiation"],
    visibility = ["//visibility:public"],
)

# Explicitly disables template_instantiation for a target.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "no_template_instantiation",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["no_template_instantiation"],
    visibility = ["//visibility:public"],
)

# A feature set enabling generating `rs_std::Tuple` everywhere.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "layout_compat_tuple",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["layout_compat_tuple"],
    visibility = ["//visibility:public"],
)

# A feature set enabling generating the layout-compatible string type everywhere.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "layout_compat_string",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["layout_compat_string"],
    visibility = ["//visibility:public"],
)

# A feature set enabling the layout-compatible optional type in by-value positions, instead of
# bridging `std::optional<T>` to a Rust `Option<T>`. Positions which cannot hold a bridged type,
# such as struct fields, pointees, and template arguments, use it regardless of this feature.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "layout_compat_optional",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["layout_compat_optional"],
    visibility = ["//visibility:public"],
)

# A feature set enabling specialization of standard library generics (like Option/Result)
# everywhere instead of composable bridging. This flag only impacts cpp_api_from_rust users,
# and has no impact on rust_api_from_cpp users.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "always_specialize_generics_in_cpp_api_from_rust",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["always_specialize_generics_in_cpp_api_from_rust"],
    visibility = ["//visibility:public"],
)

# A feature set enabling custom Debug impls for records.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "record_impl_debug",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["record_impl_debug"],
    visibility = ["//visibility:public"],
)

# A feature set enabling converting `impl Ctor<Output=T>` parameters to plain `T` instead of `T&&`.
# This flag only impacts cpp_api_from_rust users.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "ctor_plain_values",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["ctor_plain_values"],
    visibility = ["//visibility:public"],
)

# A feature set that emits some accessor code directly instead of using thunks.
#
# See b/482092715
crubit_feature_hint(
    name = "thunkless_accessors",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["thunkless_accessors"],
    visibility = ["//visibility:public"],
)

# A feature set enabling OO casting.
#
# See crubit.rs-features#other
crubit_feature_hint(
    name = "oo_casting",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["oo_casting"],
    visibility = ["//visibility:public"],
)

# A feature set enabling generating `*View` and `*Mut` directly for C++ proto references.
#
# See b/534900713
crubit_feature_hint(
    name = "proto_references",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["proto_references"],
    visibility = ["//visibility:public"],
)

# A feature set enabling generating bindings for generic types.
#
# See b/259749095
crubit_feature_hint(
    name = "generics",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["generics"],
    visibility = ["//visibility:public"],
)

# A feature set enabling the `cc_std::std::NonNull` bridge in both directions: `absl_nonnull` on
# `std::unique_ptr` and `std::shared_ptr` generates `NonNull`-wrapped Rust types, and a `NonNull`
# in a Rust API generates the wrapped C++ pointer type with the `crubit_nonnull` attribute.
#
# Visible only to Crubit itself: the meaning of this feature will change (crubit.rs-nullable), so
# it must not gain users outside Crubit's own tests in the meantime.
crubit_feature_hint(
    name = "nonnull_smart_pointers",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["nonnull_smart_pointers"],
    visibility = ["//:__subpackages__"],
)

# A feature set enabling `::cxx::ExternType` implementations for records.
crubit_feature_hint(
    name = "impl_cxx_extern_type",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["impl_cxx_extern_type"],
    visibility = ["//visibility:public"],
)

# Explicitly disables `impl_cxx_extern_type` for a target.
crubit_feature_hint(
    name = "no_impl_cxx_extern_type",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["no_impl_cxx_extern_type"],
    visibility = ["//visibility:public"],
)

# A feature set enabling the v2 C++ API for Rust enums: one nested struct per variant, built with
# `E::V::Make(...)` and inspected with `rs::get_if` and friends. This flag only impacts
# cpp_api_from_rust users.
#
# See crubit.rs-enum-api-v2 and b/489126000
crubit_feature_hint(
    name = "enum_api_v2",
    compatible_with = ["//buildenv/target:non_prod"],
    crubit_features = SUPPORTED_FEATURES + ["enum_api_v2"],
    visibility = ["//visibility:public"],
)

# Implementation details follow.

bzl_library(
    name = "crubit_feature_hint_bzl",
    srcs = ["crubit_feature_hint.bzl"],
    visibility = [
        "//:__subpackages__",
    ],
    deps = [":global_features_bzl"],
)

bzl_library(
    name = "global_features_bzl",
    srcs = ["global_features.bzl"],
    visibility = [
        "//:__subpackages__",
    ],
)
