diff --git a/crates/ruff_formatter/src/builders.rs b/crates/ruff_formatter/src/builders.rs index 1f3ef8fff1..441fb00a95 100644 --- a/crates/ruff_formatter/src/builders.rs +++ b/crates/ruff_formatter/src/builders.rs @@ -528,7 +528,22 @@ impl Format for LineSuffixBoundary { /// use ruff_formatter::prelude::*; /// use ruff_formatter::{format, write, LineWidth}; /// -/// enum SomeLabelId {} +/// #[derive(Debug, Copy, Clone)] +/// enum MyLabels { +/// Main +/// } +/// +/// impl tag::LabelDefinition for MyLabels { +/// fn value(&self) -> u64 { +/// *self as u64 +/// } +/// +/// fn name(&self) -> &'static str { +/// match self { +/// Self::Main => "Main" +/// } +/// } +/// } /// /// # fn main() -> FormatResult<()> { /// let formatted = format!( @@ -537,24 +552,24 @@ impl Format for LineSuffixBoundary { /// let mut recording = f.start_recording(); /// write!(recording, [ /// labelled( -/// LabelId::of::(), +/// LabelId::of(MyLabels::Main), /// &text("'I have a label'") /// ) /// ])?; /// /// let recorded = recording.stop(); /// -/// let is_labelled = recorded.first().map_or(false, |element| element.has_label(LabelId::of::())); +/// let is_labelled = recorded.first().map_or(false, |element| element.has_label(LabelId::of(MyLabels::Main))); /// /// if is_labelled { -/// write!(f, [text(" has label SomeLabelId")]) +/// write!(f, [text(" has label `Main`")]) /// } else { -/// write!(f, [text(" doesn't have label SomeLabelId")]) +/// write!(f, [text(" doesn't have label `Main`")]) /// } /// })] /// )?; /// -/// assert_eq!("'I have a label' has label SomeLabelId", formatted.print()?.as_code()); +/// assert_eq!("'I have a label' has label `Main`", formatted.print()?.as_code()); /// # Ok(()) /// # } /// ``` diff --git a/crates/ruff_formatter/src/format_element/tag.rs b/crates/ruff_formatter/src/format_element/tag.rs index 6c8d03c20b..a443f909f0 100644 --- a/crates/ruff_formatter/src/format_element/tag.rs +++ b/crates/ruff_formatter/src/format_element/tag.rs @@ -1,8 +1,5 @@ use crate::format_element::PrintMode; use crate::{GroupId, TextSize}; -#[cfg(debug_assertions)] -use std::any::type_name; -use std::any::TypeId; use std::cell::Cell; use std::num::NonZeroU8; @@ -235,37 +232,48 @@ impl Align { } } -#[derive(Eq, PartialEq, Copy, Clone)] +#[derive(Debug, Eq, Copy, Clone)] pub struct LabelId { - id: TypeId, + value: u64, #[cfg(debug_assertions)] - label: &'static str, + name: &'static str, } -#[cfg(debug_assertions)] -impl std::fmt::Debug for LabelId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(self.label) - } -} +impl PartialEq for LabelId { + fn eq(&self, other: &Self) -> bool { + let is_equal = self.value == other.value; -#[cfg(not(debug_assertions))] -impl std::fmt::Debug for LabelId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::write!(f, "#{:?}", self.id) + #[cfg(debug_assertions)] + { + if is_equal { + assert_eq!(self.name, other.name, "Two `LabelId`s with different names have the same `value`. Are you mixing labels of two different `LabelDefinition` or are the values returned by the `LabelDefinition` not unique?"); + } + } + + is_equal } } impl LabelId { - pub fn of() -> Self { + pub fn of(label: T) -> Self { Self { - id: TypeId::of::(), + value: label.value(), #[cfg(debug_assertions)] - label: type_name::(), + name: label.name(), } } } +/// Defines the valid labels of a language. You want to have at most one implementation per formatter +/// project. +pub trait LabelDefinition { + /// Returns the `u64` uniquely identifying this specific label. + fn value(&self) -> u64; + + /// Returns the name of the label that is shown in debug builds. + fn name(&self) -> &'static str; +} + #[derive(Clone, Copy, Eq, PartialEq, Debug)] pub enum VerbatimKind { Bogus,