summaryrefslogtreecommitdiff
path: root/subprojects/thiserror/impl/src/valid.rs
diff options
context:
space:
mode:
authorJohn Turner <jturner.usa@gmail.com>2025-12-21 04:20:53 +0000
committerJohn Turner <jturner.usa@gmail.com>2025-12-22 08:05:20 +0000
commit96708614ba46c42f87b23f2a957c510499d8811e (patch)
tree372dcf90f1a6fdf1b90f5d006ce7a32717f47166 /subprojects/thiserror/impl/src/valid.rs
parent0ec856797256b5d9807929e1b32c03756eb43124 (diff)
downloadgentoo-utils-feature/port-to-meson-cargo.tar.gz
Use the new unstable meson cargo support. This simplifies the meson.build script and allows to use crates such as clap that require picking up features from Cargo.toml. This also allows us to not embed thiserror in subprojects, and instead use a wrap file with a custom meson.build and some patches to make it compile without running its build.rs script.
Diffstat (limited to 'subprojects/thiserror/impl/src/valid.rs')
-rw-r--r--subprojects/thiserror/impl/src/valid.rs248
1 files changed, 0 insertions, 248 deletions
diff --git a/subprojects/thiserror/impl/src/valid.rs b/subprojects/thiserror/impl/src/valid.rs
deleted file mode 100644
index 21bd885..0000000
--- a/subprojects/thiserror/impl/src/valid.rs
+++ /dev/null
@@ -1,248 +0,0 @@
-use crate::ast::{Enum, Field, Input, Struct, Variant};
-use crate::attr::Attrs;
-use syn::{Error, GenericArgument, PathArguments, Result, Type};
-
-impl Input<'_> {
- pub(crate) fn validate(&self) -> Result<()> {
- match self {
- Input::Struct(input) => input.validate(),
- Input::Enum(input) => input.validate(),
- }
- }
-}
-
-impl Struct<'_> {
- fn validate(&self) -> Result<()> {
- check_non_field_attrs(&self.attrs)?;
- if let Some(transparent) = self.attrs.transparent {
- if self.fields.len() != 1 {
- return Err(Error::new_spanned(
- transparent.original,
- "#[error(transparent)] requires exactly one field",
- ));
- }
- if let Some(source) = self.fields.iter().find_map(|f| f.attrs.source) {
- return Err(Error::new_spanned(
- source.original,
- "transparent error struct can't contain #[source]",
- ));
- }
- }
- if let Some(fmt) = &self.attrs.fmt {
- return Err(Error::new_spanned(
- fmt.original,
- "#[error(fmt = ...)] is only supported in enums; for a struct, handwrite your own Display impl",
- ));
- }
- check_field_attrs(&self.fields)?;
- for field in &self.fields {
- field.validate()?;
- }
- Ok(())
- }
-}
-
-impl Enum<'_> {
- fn validate(&self) -> Result<()> {
- check_non_field_attrs(&self.attrs)?;
- let has_display = self.has_display();
- for variant in &self.variants {
- variant.validate()?;
- if has_display
- && variant.attrs.display.is_none()
- && variant.attrs.transparent.is_none()
- && variant.attrs.fmt.is_none()
- {
- return Err(Error::new_spanned(
- variant.original,
- "missing #[error(\"...\")] display attribute",
- ));
- }
- }
- Ok(())
- }
-}
-
-impl Variant<'_> {
- fn validate(&self) -> Result<()> {
- check_non_field_attrs(&self.attrs)?;
- if self.attrs.transparent.is_some() {
- if self.fields.len() != 1 {
- return Err(Error::new_spanned(
- self.original,
- "#[error(transparent)] requires exactly one field",
- ));
- }
- if let Some(source) = self.fields.iter().find_map(|f| f.attrs.source) {
- return Err(Error::new_spanned(
- source.original,
- "transparent variant can't contain #[source]",
- ));
- }
- }
- check_field_attrs(&self.fields)?;
- for field in &self.fields {
- field.validate()?;
- }
- Ok(())
- }
-}
-
-impl Field<'_> {
- fn validate(&self) -> Result<()> {
- if let Some(unexpected_display_attr) = if let Some(display) = &self.attrs.display {
- Some(display.original)
- } else if let Some(fmt) = &self.attrs.fmt {
- Some(fmt.original)
- } else {
- None
- } {
- return Err(Error::new_spanned(
- unexpected_display_attr,
- "not expected here; the #[error(...)] attribute belongs on top of a struct or an enum variant",
- ));
- }
- Ok(())
- }
-}
-
-fn check_non_field_attrs(attrs: &Attrs) -> Result<()> {
- if let Some(from) = &attrs.from {
- return Err(Error::new_spanned(
- from.original,
- "not expected here; the #[from] attribute belongs on a specific field",
- ));
- }
- if let Some(source) = &attrs.source {
- return Err(Error::new_spanned(
- source.original,
- "not expected here; the #[source] attribute belongs on a specific field",
- ));
- }
- if let Some(backtrace) = &attrs.backtrace {
- return Err(Error::new_spanned(
- backtrace,
- "not expected here; the #[backtrace] attribute belongs on a specific field",
- ));
- }
- if attrs.transparent.is_some() {
- if let Some(display) = &attrs.display {
- return Err(Error::new_spanned(
- display.original,
- "cannot have both #[error(transparent)] and a display attribute",
- ));
- }
- if let Some(fmt) = &attrs.fmt {
- return Err(Error::new_spanned(
- fmt.original,
- "cannot have both #[error(transparent)] and #[error(fmt = ...)]",
- ));
- }
- } else if let (Some(display), Some(_)) = (&attrs.display, &attrs.fmt) {
- return Err(Error::new_spanned(
- display.original,
- "cannot have both #[error(fmt = ...)] and a format arguments attribute",
- ));
- }
-
- Ok(())
-}
-
-fn check_field_attrs(fields: &[Field]) -> Result<()> {
- let mut from_field = None;
- let mut source_field = None;
- let mut backtrace_field = None;
- let mut has_backtrace = false;
- for field in fields {
- if let Some(from) = field.attrs.from {
- if from_field.is_some() {
- return Err(Error::new_spanned(
- from.original,
- "duplicate #[from] attribute",
- ));
- }
- from_field = Some(field);
- }
- if let Some(source) = field.attrs.source {
- if source_field.is_some() {
- return Err(Error::new_spanned(
- source.original,
- "duplicate #[source] attribute",
- ));
- }
- source_field = Some(field);
- }
- if let Some(backtrace) = field.attrs.backtrace {
- if backtrace_field.is_some() {
- return Err(Error::new_spanned(
- backtrace,
- "duplicate #[backtrace] attribute",
- ));
- }
- backtrace_field = Some(field);
- has_backtrace = true;
- }
- if let Some(transparent) = field.attrs.transparent {
- return Err(Error::new_spanned(
- transparent.original,
- "#[error(transparent)] needs to go outside the enum or struct, not on an individual field",
- ));
- }
- has_backtrace |= field.is_backtrace();
- }
- if let (Some(from_field), Some(source_field)) = (from_field, source_field) {
- if from_field.member != source_field.member {
- return Err(Error::new_spanned(
- from_field.attrs.from.unwrap().original,
- "#[from] is only supported on the source field, not any other field",
- ));
- }
- }
- if let Some(from_field) = from_field {
- let max_expected_fields = match backtrace_field {
- Some(backtrace_field) => 1 + (from_field.member != backtrace_field.member) as usize,
- None => 1 + has_backtrace as usize,
- };
- if fields.len() > max_expected_fields {
- return Err(Error::new_spanned(
- from_field.attrs.from.unwrap().original,
- "deriving From requires no fields other than source and backtrace",
- ));
- }
- }
- if let Some(source_field) = source_field.or(from_field) {
- if contains_non_static_lifetime(source_field.ty) {
- return Err(Error::new_spanned(
- &source_field.original.ty,
- "non-static lifetimes are not allowed in the source of an error, because std::error::Error requires the source is dyn Error + 'static",
- ));
- }
- }
- Ok(())
-}
-
-fn contains_non_static_lifetime(ty: &Type) -> bool {
- match ty {
- Type::Path(ty) => {
- let bracketed = match &ty.path.segments.last().unwrap().arguments {
- PathArguments::AngleBracketed(bracketed) => bracketed,
- _ => return false,
- };
- for arg in &bracketed.args {
- match arg {
- GenericArgument::Type(ty) if contains_non_static_lifetime(ty) => return true,
- GenericArgument::Lifetime(lifetime) if lifetime.ident != "static" => {
- return true
- }
- _ => {}
- }
- }
- false
- }
- Type::Reference(ty) => ty
- .lifetime
- .as_ref()
- .map_or(false, |lifetime| lifetime.ident != "static"),
- _ => false, // maybe implement later if there are common other cases
- }
-}