Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DiplayWithDb #477

Open
gavrilikhin-d opened this issue Mar 19, 2024 · 4 comments
Open

Add DiplayWithDb #477

gavrilikhin-d opened this issue Mar 19, 2024 · 4 comments

Comments

@gavrilikhin-d
Copy link

Add trait to Display items with database

@xiyuzhai
Copy link

Haha, I already add this trait in my personal customized version of salsa

@gavrilikhin-d
Copy link
Author

@xiyuzhai how did you do it? I have troubles with references lifetimes

@xiyuzhai
Copy link

xiyuzhai commented Mar 22, 2024

https://github.com/xiyuzhai-husky-lang/husky/blob/main/crates/abstractions/salsa/src/display.rs

I imitated DebugWithDb's implementation. However, my implementation differs from salsa in that I remove the generic parameter Db, and use a single Db type for the whole workspace to save compilation time significantly.


pub trait DisplayWithDb {
    fn display<'me, 'db>(&'me self, db: &'me Db) -> DisplayWith<'me>
    where
        Self: Sized + 'me,
    {
        DisplayWith {
            value: BoxRef::Ref(self),
            db,
        }
    }

    fn display_with<'me, 'db>(&'me self, db: &'me Db) -> DisplayWith<'me>
    where
        Self: Sized + 'me,
    {
        DisplayWith {
            value: BoxRef::Ref(self),
            db,
        }
    }

    /// if `level` is `false` only identity fields should be read, which means:
    ///     - for [#\[salsa::input\]](salsa_macros::input) no fields
    ///     - for [#\[salsa::tracked\]](salsa_macros::tracked) only fields with `#[id]` attribute
    ///     - for [#\[salsa::interned\]](salsa_macros::interned) any field
    fn display_fmt_with_db(&self, f: &mut fmt::Formatter<'_>, db: &Db) -> fmt::Result;
}

@gavrilikhin-d
Copy link
Author

gavrilikhin-d commented Mar 22, 2024

I came up with something like this at the end:

use std::fmt::{self, Display, Formatter, FormatterFn};

pub trait DisplayWithDb<'me, DB: ?Sized + 'me> {
    fn fmt_with(&self, db: &DB, f: &mut Formatter<'_>) -> fmt::Result;

    fn display_with(&self, db: &DB) -> FormatterFn<impl Fn(&mut Formatter<'_>) -> fmt::Result> {
        FormatterFn(|f| self.fmt_with(db, f)) // Unstable rust. Write a struct wrapper, if you want to use stable rust
    }

    fn to_string_with(&self, db: &DB) -> String {
        self.display_with(db).to_string()
    }
}

impl<'me, DB: ?Sized + 'me, D: Display> DisplayWithDb<'me, DB> for D {
    fn fmt_with(&self, _db: &DB, f: &mut Formatter<'_>) -> fmt::Result {
        Display::fmt(&self, f)
    }
}

Implement it like this:

#[salsa::interned]
pub struct Typename {
    #[return_ref]
    pub text: String,
}

impl<'me> DisplayWithDb<'me, dyn Db + 'me> for Typename {
    fn fmt_with(&self, db: &dyn Db, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.text(db))
    }
}

There is something tricky with dyn Db lifetimes that forces me to specify them explicitly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants