Repository: alacritty/alacritty
File: alacritty_terminal/src/term/cell.rs (Rust)

Code before:
    pub(crate) fn set_underline_color(&mut self, color: Option<Color>) {
        let extra = match self.extra.as_mut() {
            Some(extra) if Rc::strong_count(extra) == 1 => extra,
            extra @ _ => {
                self.extra =
                    Some(Rc::new(extra.map(|extra| (**extra).clone()).unwrap_or_default()));
                self.extra.as_mut().unwrap()
            },
        };

        // We've ensured that particular arc, since we don't have weak refs, only strong.
        let extra = Rc::get_mut(extra).unwrap();
        extra.underline_color = color;
    }

    /// Underline color stored in this cell.
    #[inline]
    pub fn undreline_color(&self) -> Option<Color> {
        self.extra.as_ref()?.underline_color
    }
}

unsafe impl Send for Cell {}
unsafe impl Sync for Cell {}

impl GridCell for Cell {
    #[inline]
    fn is_empty(&self) -> bool {
        (self.c == ' ' || self.c == '\t')
            && self.bg == Color::Named(NamedColor::Background)
            && self.fg == Color::Named(NamedColor::Foreground)
            && !self.flags.intersects(
                Flags::INVERSE
                    | Flags::ALL_UNDERLINES
                    | Flags::STRIKEOUT
                    | Flags::WRAPLINE
                    | Flags::WIDE_CHAR_SPACER
                    | Flags::LEADING_WIDE_CHAR_SPACER,
            )
            && self.extra.as_ref().map(|extra| extra.zerowidth.is_empty()) != Some(false)
    }

    #[inline]
    fn flags(&self) -> &Flags {
        &self.flags
    }

    #[inline]
    fn flags_mut(&mut self) -> &mut Flags {
        &mut self.flags
    }

Review comment (bug):
This is wrong, however if we change clone impl so it clones the underlines extra storage and puts it into Rc it'll be fine? And we won't allow to modify the extra storage outside of Terminal.

Since the terminal is behind mutex in alacritty it's safe the way it's right now, however it won't be so if you move cell into another thread.

Code after:
}

impl GridCell for Cell {
    #[inline]
    fn is_empty(&self) -> bool {
        (self.c == ' ' || self.c == '\t')
            && self.bg == Color::Named(NamedColor::Background)
            && self.fg == Color::Named(NamedColor::Foreground)
            && !self.flags.intersects(
                Flags::INVERSE
                    | Flags::ALL_UNDERLINES
                    | Flags::STRIKEOUT
                    | Flags::WRAPLINE
                    | Flags::WIDE_CHAR_SPACER
                    | Flags::LEADING_WIDE_CHAR_SPACER,
            )
            && self.extra.as_ref().map(|extra| extra.zerowidth.is_empty()) != Some(false)
    }

    #[inline]
    fn flags(&self) -> &Flags {
        &self.flags
    }

    #[inline]
    fn flags_mut(&mut self) -> &mut Flags {
        &mut self.flags
    }

    #[inline]
    fn reset(&mut self, template: &Self) {
        *self = Cell { bg: template.bg, ..Cell::default() };
    }
}

impl From<Color> for Cell {
    #[inline]
    fn from(color: Color) -> Self {
        Self { bg: color, ..Cell::default() }
    }
}

/// Get the length of occupied cells in a line.
pub trait LineLength {
    /// Calculate the occupied line length.
    fn line_length(&self) -> Column;
}

impl LineLength for grid::Row<Cell> {
    fn line_length(&self) -> Column {
        let mut length = Column(0);