Repository: servo/servo
File: components/script_bindings/domstring.rs (Rust)

Code before:
        // BytesView will just give the raw bytes on dereference.
        // If we are ascii this is the same for latin1 and utf8.
        // Otherwise we convert to rust.
        if self.is_ascii() {
            BytesView(BytesViewWrapper(self.0.borrow()))
        } else {
            self.make_rust();
            BytesView(BytesViewWrapper(self.0.borrow()))
        }
    }

    /// Tests if there are only ascii lowercase characters. Does not include special characters.
    pub fn is_ascii_lowercase(&self) -> bool {
        match self.view().encoded_bytes() {
            EncodedBytes::Latin1Bytes(items) => items
                .iter()
                .all(|c| (ASCII_LOWERCASE_A..=ASCII_LOWERCASE_Z).contains(c)),
            EncodedBytes::Utf8Bytes(s) => s
                .iter()
                .map(|c| c.to_u8().unwrap_or(ASCII_LOWERCASE_A - 1))
                .all(|c| (ASCII_LOWERCASE_A..=ASCII_LOWERCASE_Z).contains(&c)),
        }
    }

    /// Only use this if your string does not use any characters that are non-ascii
    pub fn eq_ascii(&self, needle: &str) -> bool {
        debug_assert!(needle.is_ascii());
        match self.view().encoded_bytes() {
            EncodedBytes::Latin1Bytes(items) => needle.as_bytes() == items,
            EncodedBytes::Utf8Bytes(s) => {
                unsafe {
                    // Save because we know it was a utf8 string
                    str::from_utf8_unchecked(s) == needle
                }
            },
        }
    }

    /// Is the string only ascii characters
    pub fn is_ascii(&self) -> bool {
        match self.view().encoded_bytes() {
            EncodedBytes::Latin1Bytes(items) => items,
            EncodedBytes::Utf8Bytes(items) => items,
        }
        .is_ascii()
    }
}

/// <https://html.spec.whatwg.org/multipage/#rules-for-parsing-floating-point-number-values>
pub fn parse_floating_point_number(input: &str) -> Option<f64> {
    // Steps 15-16 are telling us things about IEEE rounding modes

Review comment (suggestion):
We could make a `struct AsciiStr<'a>(&'a str)` to enforce this with the type system. That type could have a const constructor that takes a &str and asserts that is_ascii is true, since that is available in const contexts.

Code after:
        // BytesView will just give the raw bytes on dereference.
        // If we are ascii this is the same for latin1 and utf8.
        // Otherwise we convert to rust.
        if self.is_ascii() {
            BytesView(self.0.borrow())
        } else {
            self.make_rust();
            BytesView(self.0.borrow())
        }
    }

    /// Tests if there are only ascii lowercase characters. Does not include special characters.
    pub fn is_ascii_lowercase(&self) -> bool {
        match self.view().encoded_bytes() {
            EncodedBytes::Latin1Bytes(items) => items
                .iter()
                .all(|c| (ASCII_LOWERCASE_A..=ASCII_LOWERCASE_Z).contains(c)),
            EncodedBytes::Utf8Bytes(s) => s
                .iter()
                .map(|c| c.to_u8().unwrap_or(ASCII_LOWERCASE_A - 1))
                .all(|c| (ASCII_LOWERCASE_A..=ASCII_LOWERCASE_Z).contains(&c)),
        }
    }

    /// Is the string only ascii characters
    pub fn is_ascii(&self) -> bool {
        match self.view().encoded_bytes() {
            EncodedBytes::Latin1Bytes(items) => items,
            EncodedBytes::Utf8Bytes(items) => items,
        }
        .is_ascii()
    }
}

/// <https://html.spec.whatwg.org/multipage/#rules-for-parsing-floating-point-number-values>
pub fn parse_floating_point_number(input: &str) -> Option<f64> {
    // Steps 15-16 are telling us things about IEEE rounding modes
    // for floating-point significands; this code assumes the Rust
    // compiler already matches them in any cases where
    // that actually matters. They are not
    // related to f64::round(), which is for rounding to integers.
    input.trim().parse::<f64>().ok().filter(|value| {
        // A valid number is the same as what rust considers to be valid,
        // except for +1., NaN, and Infinity.
        !(value.is_infinite() || value.is_nan() || input.ends_with('.') || input.starts_with('+'))
    })
}

pub struct BytesView<'a>(Ref<'a, DOMStringType>);

impl Deref for BytesView<'_> {