Use trait for labels instead of TypeId (#5270)

This commit is contained in:
Micha Reiser 2023-06-21 23:26:09 +02:00 committed by GitHub
parent 1eccbbb60e
commit 3d7411bfaf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 25 deletions

View file

@ -528,7 +528,22 @@ impl<Context> Format<Context> for LineSuffixBoundary {
/// use ruff_formatter::prelude::*; /// use ruff_formatter::prelude::*;
/// use ruff_formatter::{format, write, LineWidth}; /// 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<()> { /// # fn main() -> FormatResult<()> {
/// let formatted = format!( /// let formatted = format!(
@ -537,24 +552,24 @@ impl<Context> Format<Context> for LineSuffixBoundary {
/// let mut recording = f.start_recording(); /// let mut recording = f.start_recording();
/// write!(recording, [ /// write!(recording, [
/// labelled( /// labelled(
/// LabelId::of::<SomeLabelId>(), /// LabelId::of(MyLabels::Main),
/// &text("'I have a label'") /// &text("'I have a label'")
/// ) /// )
/// ])?; /// ])?;
/// ///
/// let recorded = recording.stop(); /// let recorded = recording.stop();
/// ///
/// let is_labelled = recorded.first().map_or(false, |element| element.has_label(LabelId::of::<SomeLabelId>())); /// let is_labelled = recorded.first().map_or(false, |element| element.has_label(LabelId::of(MyLabels::Main)));
/// ///
/// if is_labelled { /// if is_labelled {
/// write!(f, [text(" has label SomeLabelId")]) /// write!(f, [text(" has label `Main`")])
/// } else { /// } 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(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```

View file

@ -1,8 +1,5 @@
use crate::format_element::PrintMode; use crate::format_element::PrintMode;
use crate::{GroupId, TextSize}; use crate::{GroupId, TextSize};
#[cfg(debug_assertions)]
use std::any::type_name;
use std::any::TypeId;
use std::cell::Cell; use std::cell::Cell;
use std::num::NonZeroU8; use std::num::NonZeroU8;
@ -235,37 +232,48 @@ impl Align {
} }
} }
#[derive(Eq, PartialEq, Copy, Clone)] #[derive(Debug, Eq, Copy, Clone)]
pub struct LabelId { pub struct LabelId {
id: TypeId, value: u64,
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
label: &'static str, name: &'static str,
} }
impl PartialEq for LabelId {
fn eq(&self, other: &Self) -> bool {
let is_equal = self.value == other.value;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
impl std::fmt::Debug for LabelId { {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if is_equal {
f.write_str(self.label) 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?");
} }
} }
#[cfg(not(debug_assertions))] is_equal
impl std::fmt::Debug for LabelId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::write!(f, "#{:?}", self.id)
} }
} }
impl LabelId { impl LabelId {
pub fn of<T: ?Sized + 'static>() -> Self { pub fn of<T: LabelDefinition>(label: T) -> Self {
Self { Self {
id: TypeId::of::<T>(), value: label.value(),
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
label: type_name::<T>(), 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)] #[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum VerbatimKind { pub enum VerbatimKind {
Bogus, Bogus,