You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: tokenizer.rs
    path of file: ./repos/gosub-engine/crates/gosub_css3/src
    
    the code of the file until where you have to start completion: use crate::location::Location;
use crate::unicode::{get_unicode_char, UnicodeChar};
use gosub_shared::byte_stream::Character::Ch;
use gosub_shared::byte_stream::{ByteStream, Character, Stream};
use std::fmt;
use std::usize;

pub type Number = f32;

#[derive(Debug, PartialEq, Clone)]
pub enum TokenType {
    /// A [`<at-keyword-token>`](https://drafts.csswg.org/css-syntax/#at-keyword-token-diagram)
    ///
    /// The value does not include the `@` marker.
    AtKeyword(String),
    Ident(String),
    Function(String),
    Url(String),
    BadUrl(String),
    Dimension {
        value: Number,
        unit: String,
    },
    Percentage(Number),
    Number(Number),
    /// A [`<string-token>`](https://drafts.csswg.org/css-syntax/#string-token-diagram)
    ///
    /// The value does not include the quotes.
    QuotedString(String),
    /// A `<bad-string-token>`
    ///
    /// This token always indicates a parse error.
    BadString(String),
    /// A [`<whitespace-token>`](https://drafts.csswg.org/css-syntax/#whitespace-token-diagram)
    Whitespace,
    /// A [`<hash-token>`](https://drafts.csswg.org/css-syntax/#hash-token-diagram) with the type flag set to "unrestricted"
    ///
    /// The value does not include the `#` marker.
    Hash(String),
    /// A [`<hash-token>`](https://drafts.csswg.org/css-syntax/#hash-token-diagram) with the type flag set to "id"
    ///
    /// The value does not include the `#` marker.
    ///
    /// Hash that is a valid ID selector.
    IDHash(String),
    /// A `<delim-token>`
    Delim(char),
    /// A `<{-token>`
    LCurly,
    /// A `<}-token>`
    RCurly,
    /// A `<(-token>`
    LParen,
    /// A `<)-token>`
    RParen,
    /// A `<[-token>`
    LBracket,
    /// A `<]-token>`
    RBracket,
    /// A `<comma-token>`
    Comma,
    /// A `:` `<colon-token>`
    Colon,
    /// A `;` `<semicolon-token>`
    Semicolon,
    // A `<!--` `<CDO-token>`
    Cdo,
    // A `-->` `<CDC-token>`
    Cdc,
    // // A `<EOF-token>`
    Eof,
    // A comment
    Comment(String),
}

#[derive(Clone, PartialEq, Debug)]
pub struct Token {
    /// Type of the token
    pub token_type: TokenType,
    /// Location of the token in the stream
    pub location: Location,
}

impl Token {
    /// Returns a new token for the given type on the given location
    fn new(token_type: TokenType, location: Location) -> Token {
        Token {
            token_type,
            location,
        }
    }

    fn new_delim(c: char, location: Location) -> Token {
        Token::new(TokenType::Delim(c), location)
    }

    fn new_id_hash(value: &str, location: Location) -> Token {
        Token::new(TokenType::IDHash(value.to_string()), location)
    }

    fn new_hash(value: &str, location: Location) -> Token {
        Token::new(TokenType
    
    fn consume_token(&mut self) -> Token {
        while self.look_ahead_slice(2) == "/*" {
            self.consume_comment();
        }

        // todo: reframe the concept of "tokenizer::current" and "is::current" and "is::next"
        let current = self.current_char();
        let loc = self.current_location().clone();

        let t = match current {
            Character::Surrogate(_) => {
                self.next_char();
                // @todo: we found a surrogate. Just return a replacement char
                Token::new(TokenType::Delim('\u{FFFD}'), loc)
            }
            Character::StreamEnd => Token::new(TokenType::Eof, loc),
            Character::StreamEmpty => {
                // @todo: we are in a situation where we don't have more characters yet, but the stream is still open. We should wait
                // for more characters to come in.
                Token::new(TokenType::Eof, loc)
            }
            Ch(c) if c.is_whitespace() => {
                self.consume_whitespace();
                Token::new(TokenType::Whitespace, loc)
            }
            // note: consume_string_token doesn't work as expected
            Ch('"' | '\'') => self.consume_string_token(),
            Ch(c @ '#') => {
                // consume '#'
                self.next_char();

                if self.is_ident_char(self.current_char().into()) || self.is_start_of_escape(0) {
                    return if self.is_next_3_points_starts_ident_seq(0) {
                        Token::new_id_hash(self.consume_ident().as_str(), loc)
                    } else {
                        Token::new_hash(self.consume_ident().as_str(), loc)
                    };
                }

                Token::new_delim(c, loc)
            }
            Ch(')') => {
                self.next_char();
                Token::new(TokenType::RParen, loc)
            }
            Ch('(') => {
                self.next_char();
                Token::new(TokenType::LParen, loc)
            }
            Ch('[') => {
                self.next_char();
                Token::new(TokenType::LBracket, loc)
            }
            Ch(']') => {
                self.next_char();
                Token::new(TokenType::RBracket, loc)
            }
            Ch('{') => {
                self.next_char();
                Token::new(TokenType::LCurly, loc)
            }
            Ch('}') => {
                self.next_char();
                Token::new(TokenType::RCurly, loc)
            }
            Ch(',') => {
                self.next_char();
                Token::new(TokenType::Comma, loc)
            }
            Ch(':') => {
                self.next_char();
                Token::new(TokenType::Colon, loc)
            }
            Ch(';') => {
                self.next_char();
                Token::new(TokenType::Semicolon, loc)
            }
            Ch(c @ '+') => {
                if self.is_signed_decimal(0) {
                    return self.consume_numeric_token();
                }

                // consume '+'
                self.next_char();
                Token::new_delim(c, loc)
            }
            Ch('.') => {
                if matches!(self.stream.look_ahead(1), Ch(c) if c.is_numeric()) {
                    return self.consume_numeric_token();
                }

                // consume '.'
                self.next_char();
                Token::new_delim('.', loc)
            }
            Ch(c @ '-') => {
                if self.is_signed_decimal(0) {
                    return self.consume_numeric_token();
                }

                let cdc_token = "-->";
                if self.look_ahead_slice(cdc_token.len()) == cdc_token {
                    // consume '--'
                    self.consume_chars(cdc_token.len());
                    return Token::new(TokenType::Cdc, loc);
                }

                if self.is_next_3_points_starts_ident_seq(0) {
                    return self.consume_ident_like_seq();
                }

                // consume '-'
                self.next_char();
                Token::new_delim(c, loc)
            }
            Ch(c @ '<') => {
                let cdo_token = "<!--";
                if self.look_ahead_slice(cdo_token.len()) == cdo_token {
                    // consume "<!--"
                    self.consume_chars(cdo_token.len());
                    return Token::new(TokenType::Cdo, loc);
                }

                // consume '<'
                self.next_char();
                Token::new_delim(c, loc)
            }
            Ch(c @ '@') => {
                // consume '@'
                self.next_char();

                if self.is_next_3_points_starts_ident_seq(0) {
                    return Token::new_atkeyword(self.consume_ident().as_str(), loc);
                }

                Token::new_delim(c, loc)
            }
            Ch(c @ '\\') => {
                if self.is_start_of_escape(0) {
                    return self.consume_ident_like_seq();
                }

                // parser error
                // consume '\'
                self.next_char();
                Token::new_delim(c, loc)
            }
            Ch(c) if c.is_numeric() => self.consume_numeric_token(),
            Ch(c) if self.is_ident_start(c) => self.consume_ident_like_seq(),
            Ch(c) => {
                self.next_char();
                Token::new(TokenType::Delim(c), loc)
            }
        };

        t
    }