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: trampoline.rs
    path of file: ./repos/artichoke/artichoke-backend/src/extn/core/string
    
    the code of the file until where you have to start completion: #![allow(clippy::cast_possible_wrap)]

use core::convert::TryFrom;
use core::fmt::Write as _;
use core::hash::BuildHasher;
use core::str;

use artichoke_core::hash::Hash as _;
use artichoke_core::value::Value as _;
use bstr::ByteSlice;

use super::Encoding;
use crate::convert::implicitly_convert_to_int;
use crate::convert::implicitly_convert_to_nilable_string;
use crate::convert::implicitly_convert_to_spinoso_string;
use crate::convert::implicitly_convert_to_string;
use crate::extn::core::array::Array;
#[cfg(feature = "core-regexp")]
use crate::extn::core::matchdata::{self, MatchData};
#[cfg(feature = "core-regexp")]
use crate::extn::core::regexp::{self, Regexp};
use crate::extn::core::symbol::Symbol;
use crate::extn::prelude::*;
use crate::sys::protect;

pub fn mul(interp: &mut Artichoke, mut value: Value, count: Value) -> Result<Value, Error> {
    let count = implicitly_convert_to_int(interp, count)?;
    let count = usize::try_from(count).map_err(|_| ArgumentError::with_message("negative argument"))?;

    let s = unsafe { super::String::unbox_from_value(&mut value, interp)? };
    // This guard ensures `repeat` below does not panic on `usize` overflow.
    if count.checked_mul(s.len()).is_none() {
        return Err(RangeError::with_message("bignum too big to convert into `long'").into());
    }
    let repeated_s = s.as_slice().repeat(count).into();
    super::String::alloc_value(repeated_s, interp)
}

pub fn add(interp: &mut Artichoke, mut value: Value, mut other: Value) -> Result<Value, Error> {
    let s = unsafe { super::String::unbox_from_value(&mut value, interp)? };
    // SAFETY: The borrowed byte slice is immediately copied into the `s` byte
    // buffer. There are no intervening interpreter accesses.
    let to_append = unsafe { implicitly_convert_to_string(interp, &mut other)? };

    let mut concatenated = s.clone();
    // XXX: This call doesn't do a check to see if we'll exceed the max allocation
    //    size and may panic or abort.
    concatenated.extend_from_slice(to_append);
    super::String::alloc_value(concatenated, interp)
}

pub fn append(interp: &mut Artichoke, mut value: Value, mut other: Value) -> Result<Value, Error> {
    if value.is_frozen(interp) {
        let s = unsafe { super::String::unbox_from_value(&mut value, interp)? };
        let message = "can't modify frozen String: "
            .chars()
            .chain(s.inspect())
            .collect::<super::String>();
        return Err(FrozenError::from(message.into_vec()).into());
    }

    let mut s = unsafe { super::String::unbox_from_value(&mut value, interp)? };
    if let Ok(int) = other.try_convert_into::<i64>(interp) {
        // SAFETY: The string is repacked before any intervening uses of
        // `interp` which means no mruby heap allocations can occur.
        unsafe {
            let string_mut = s.as_inner_mut();
            // XXX: This call doesn't do a check to see if we'll exceed the max allocation
            //    size and may panic or abort.
            string_mut
                .try_push_int(int)
                .map_err(|err| RangeError::from(err.message()))?;
            let s = s.take();
            return super::String::box_into_value(s, value, interp);
        }
    }
    // SAFETY: The byte slice is immediately used and discarded after extraction.
    // There are no intervening interpreter accesses.
    let other = unsafe { implicitly_convert_to_spinoso_string(interp, &mut other)? };
    match s.encoding() {
        // ```
        // [3.1.2] > s = ""
        // => ""
        // [3.1.2] > b = "abc".b
        // => "abc"
        // [3.1.2] > s << b
        // => "abc"
        // [3.1.2] > s.encoding
        // => #<Encoding:UTF-8>
        // [3.1.2] > b = "\xFF\xFE".b
        // => "\xFF\xFE"
        // [3.1.2] > s = ""
        // => ""
        // [3.1.2] > s << b
        // => "\xFF\xFE"
        // [3.1.2] > s.encoding
        // => #<Encoding:ASCII-8BIT>
        // [3.1.2] > s = "abc"
        // => "abc"
        // [3.1.2] > s << b
        // => "abc\xFF\xFE"
        // [3.1.2] > s.encoding
        // => #<Encoding:ASCII-8BIT>
        // [3.1.2] > s = ""
        // => ""
        // [3.1.2] > b = "abc".b
        // => "abc"
        // [3.1.2] > b.ascii_only?
        // => true
        // [3.1.2] > s << b
        // => "abc"
        // [3.1.2] > s.encoding
        // => #<Encoding:UTF-8>
        // [3.1.2] > a = "\xFF\xFE".force_encoding(Encoding::ASCII)
        // => "\xFF\xFE"
        // [3.1.2] > s = ""
        // => ""
        // [3.1.2] > s << a
        // => "\xFF\xFE"
        // [3.1.2] > s.encoding
        // => #<Encoding:US-ASCII>
        // [3.1.2] > s = "abc"
        // => "abc"
        // [3.1.2] > s << a
        // => "abc\xFF\xFE"
        // [3.1.2] > s.encoding
        // => #<Encoding:US-ASCII>
        // ```
        Encoding::Utf8 => {
            // SAFETY: The string is repacked before any intervening uses of
            // `interp` which means no mruby
    
pub fn scan(interp: &mut Artichoke, value: Value, mut pattern: Value, block: Option<Block>) -> Result<Value, Error> {
    if let Ruby::Symbol = pattern.ruby_type() {
        let mut message = String::from("wrong argument type ");
        message.push_str(interp.inspect_type_name_for_value(pattern));
        message.push_str(" (expected Regexp)");
        return Err(TypeError::from(message).into());
    }
    #[cfg(feature = "core-regexp")]
    if let Ok(regexp) = unsafe { Regexp::unbox_from_value(&mut pattern, interp) } {
        let haystack = value.try_convert_into_mut::<&[u8]>(interp)?;
        let scan = regexp.inner().scan(interp, haystack, block)?;
        return Ok(interp.try_convert_mut(scan)?.unwrap_or(value));
    }
    #[cfg(feature = "core-regexp")]
    // SAFETY: `pattern_bytes` is converted to an owned byte vec to ensure the
    // underlying `RString*` is not garbage collected when yielding matches.
    if let Ok(pattern_bytes) = unsafe { implicitly_convert_to_string(interp, &mut pattern) } {
        let pattern_bytes = pattern_bytes.to_vec();

        let string = value.try_convert_into_mut::<&[u8]>(interp)?;
        if let Some(ref block) = block {
            let regex = Regexp::try_from(pattern_bytes.clone())?;
            let matchdata = MatchData::new(string.to_vec(), regex, ..);
            let patlen = pattern_bytes.len();
            if let Some(pos) = string.find(&pattern_bytes) {
                let mut data = matchdata.clone();
                data.set_region(pos..pos + patlen);
                let data = MatchData::alloc_value(data, interp)?;
                interp.set_global_variable(regexp::LAST_MATCH, &data)?;

                let block_arg = interp.try_convert_mut(pattern_bytes.as_slice())?;
                block.yield_arg(interp, &block_arg)?;

                interp.set_global_variable(regexp::LAST_MATCH, &data)?;

                let offset = pos + patlen;
                let string = string.get(offset..).unwrap_or_default();
                for pos in string.find_iter(&pattern_bytes) {
                    let mut data = matchdata.clone();
                    data.set_region(offset + pos..offset + pos + patlen);
                    let data = MatchData::alloc_value(data, interp)?;
                    interp.set_global_variable(regexp::LAST_MATCH, &data)?;

                    let block_arg = interp.try_convert_mut(pattern_bytes.as_slice())?;
                    block.yield_arg(interp, &block_arg)?;

                    interp.set_global_variable(regexp::LAST_MATCH, &data)?;
                }
            } else {
                interp.unset_global_variable(regexp::LAST_MATCH)?;
            }
            return Ok(value);
        }
        let (matches, last_pos) = string
            .find_iter(&pattern_bytes)
            .enumerate()
            .last()
            .map(|(m, p)| (m + 1, p))
            .unwrap_or_default();
        let mut result = Vec::with_capacity(matches);
        for _ in 0..matches {
            result.push(interp.try_convert_mut(pattern_bytes.as_slice())?);
        }
        if matches > 0 {
            let regex = Regexp::try_from(pattern_bytes.clone())?;
            let matchdata = MatchData::new(string.to_vec(), regex, last_pos..last_pos + pattern_bytes.len());
            let data = MatchData::alloc_value(matchdata, interp)?;
            interp.set_global_variable(regexp::LAST_MATCH, &data)?;
        } else {
            interp.unset_global_variable(regexp::LAST_MATCH)?;
        }
        return interp.try_convert_mut(result);
    }
    #[cfg(not(feature = "core-regexp"))]
    // SAFETY: `pattern_bytes` is converted to an owned byte vec to ensure the
    // underlying `RString*` is not garbage collected when yielding matches.
    if let Ok(pattern_bytes) = unsafe { implicitly_convert_to_string(interp, &mut pattern) } {
        let pattern_bytes = pattern_bytes.to_vec();

        let string = value.try_convert_into_mut::<&[u8]>(interp)?;
        if let Some(ref block) = block {
            let patlen = pattern_bytes.len();
            if let Some(pos) = string.find(&pattern_bytes) {
                let block_arg = interp.try_convert_mut(pattern_bytes.as_slice())?;
                block.yield_arg(interp, &block_arg)?;

                let offset = pos + patlen;
                let string = string.get(offset..).unwrap_or_default();
                for _ in string.find_iter(&pattern_bytes) {
                    let block_arg = interp.try_convert_mut(pattern_bytes.as_slice())?;
                    block.yield_arg(interp, &block_arg)?;
                }
            }
            return Ok(value);
        }
        let matches = string
            .find_iter(&pattern_bytes)
            .enumerate()
            .last()
            .map(|(m, _)| m + 1)
            .unwrap_or_default();
        let mut result = Vec::with_capacity(matches);
        for _ in 0..matches {
            result.push(interp.try_convert_mut(pattern_bytes.as_slice())?);
        }
        return interp.try_convert_mut(result);
    }
    let mut message = String::from("wrong argument type ");
    message.push_str(interp.inspect_type_name_for_value(pattern));
    message.push_str(" (expected Regexp)");
    Err(TypeError::from(message).into())
}