<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use Rng;
use distributions::Distribution;
use distributions::uniform::{UniformSampler, SampleUniform, SampleBorrow};
use ::core::cmp::PartialOrd;
use core::fmt;

// Note that this whole module is only imported if feature="alloc" is enabled.
#[cfg(not(feature="std"))] use alloc::vec::Vec;

/// A distribution using weighted sampling to pick a discretely selected item.
///
/// Sampling a `WeightedIndex` distribution returns the index of a randomly
/// selected element from the iterator used when the `WeightedIndex` was
/// created. The chance of a given element being picked is proportional to the
/// value of the element. The weights can use any type `X` for which an
/// implementation of [`Uniform<X>`] exists.
///
/// # Example
///
/// ```
/// use rand::prelude::*;
/// use rand::distributions::WeightedIndex;
///
/// let choices = ['a', 'b', 'c'];
/// let weights = [2,   1,   1];
/// let dist = WeightedIndex::new(&weights).unwrap();
/// let mut rng = thread_rng();
/// for _ in 0..100 {
///     // 50% chance to print 'a', 25% chance to print 'b', 25% chance to print 'c'
///     println!("{}", choices[dist.sample(&mut rng)]);
/// }
///
/// let items = [('a', 0), ('b', 3), ('c', 7)];
/// let dist2 = WeightedIndex::new(items.iter().map(|item| item.1)).unwrap();
/// for _ in 0..100 {
///     // 0% chance to print 'a', 30% chance to print 'b', 70% chance to print 'c'
///     println!("{}", items[dist2.sample(&mut rng)].0);
/// }
/// ```
#[derive(Debug, Clone)]
pub struct WeightedIndex<X: SampleUniform + PartialOrd> {
    cumulative_weights: Vec<X>,
    weight_distribution: X::Sampler,
}

impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
    /// Creates a new a `WeightedIndex` [`Distribution`] using the values
    /// in `weights`. The weights can use any type `X` for which an
    /// implementation of [`Uniform<X>`] exists.
    ///
    /// Returns an error if the iterator is empty, if any weight is `< 0`, or
    /// if its total value is 0.
    ///
    /// [`Distribution`]: trait.Distribution.html
    /// [`Uniform<X>`]: struct.Uniform.html
    pub fn new<I>(weights: I) -> Result<WeightedIndex<X>, WeightedError>
        where I: IntoIterator,
              I::Item: SampleBorrow<X>,
              X: for<'a> ::core::ops::AddAssign<&'a X> +
                 Clone +
                 Default {
        let mut iter = weights.into_iter();
        let mut total_weight: X = iter.next()
                                      .ok_or(WeightedError::NoItem)?
                                      .borrow()
                                      .clone();

        let zero = <X as Default>::default();
        if total_weight < zero {
            return Err(WeightedError::NegativeWeight);
        }

        let mut weights = Vec::<X>::with_capacity(iter.size_hint().0);
        for w in iter {
            if *w.borrow() < zero {
                return Err(WeightedError::NegativeWeight);
            }
            weights.push(total_weight.clone());
            total_weight += w.borrow();
        }

        if total_weight == zero {
            return Err(WeightedError::AllWeightsZero);
        }
        let distr = X::Sampler::new(zero, total_weight);

        Ok(WeightedIndex { cumulative_weights: weights, weight_distribution: distr })
    }
}

impl<X> Distribution<usize> for WeightedIndex<X> where
    X: SampleUniform + PartialOrd {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
        use ::core::cmp::Ordering;
        let chosen_weight = self.weight_distribution.sample(rng);
        // Find the first item which has a weight *higher* than the chosen weight.
        self.cumulative_weights.binary_search_by(
            |w| if *w <= chosen_weight { Ordering::Less } else { Ordering::Greater }).unwrap_err()
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_weightedindex() {
        let mut r = ::test::rng(700);
        const N_REPS: u32 = 5000;
        let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7];
        let total_weight = weights.iter().sum::<u32>() as f32;

        let verify = |result: [i32; 14]| {
            for (i, count) in result.iter().enumerate() {
                let exp = (weights[i] * N_REPS) as f32 / total_weight;
                let mut err = (*count as f32 - exp).abs();
                if err != 0.0 {
                    err /= exp;
                }
                assert!(err <= 0.25);
            }
        };

        // WeightedIndex from vec
        let mut chosen = [0i32; 14];
        let distr = WeightedIndex::new(weights.to_vec()).unwrap();
        for _ in 0..N_REPS {
            chosen[distr.sample(&mut r)] += 1;
        }
        verify(chosen);

        // WeightedIndex from slice
        chosen = [0i32; 14];
        let distr = WeightedIndex::new(&weights[..]).unwrap();
        for _ in 0..N_REPS {
            chosen[distr.sample(&mut r)] += 1;
        }
        verify(chosen);

        // WeightedIndex from iterator
        chosen = [0i32; 14];
        let distr = WeightedIndex::new(weights.iter()).unwrap();
        for _ in 0..N_REPS {
            chosen[distr.sample(&mut r)] += 1;
        }
        verify(chosen);

        for _ in 0..5 {
            assert_eq!(WeightedIndex::new(&[0, 1]).unwrap().sample(&mut r), 1);
            assert_eq!(WeightedIndex::new(&[1, 0]).unwrap().sample(&mut r), 0);
            assert_eq!(WeightedIndex::new(&[0, 0, 0, 0, 10, 0]).unwrap().sample(&mut r), 4);
        }

        assert_eq!(WeightedIndex::new(&[10][0..0]).unwrap_err(), WeightedError::NoItem);
        assert_eq!(WeightedIndex::new(&[0]).unwrap_err(), WeightedError::AllWeightsZero);
        assert_eq!(WeightedIndex::new(&[10, 20, -1, 30]).unwrap_err(), WeightedError::NegativeWeight);
        assert_eq!(WeightedIndex::new(&[-10, 20, 1, 30]).unwrap_err(), WeightedError::NegativeWeight);
        assert_eq!(WeightedIndex::new(&[-10]).unwrap_err(), WeightedError::NegativeWeight);
    }
}

/// Error type returned from `WeightedIndex::new`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WeightedError {
    /// The provided iterator contained no items.
    NoItem,

    /// A weight lower than zero was used.
    NegativeWeight,

    /// All items in the provided iterator had a weight of zero.
    AllWeightsZero,
}

impl WeightedError {
    fn msg(&self) -> &str {
        match *self {
            WeightedError::NoItem => "No items found",
            WeightedError::NegativeWeight => "Item has negative weight",
            WeightedError::AllWeightsZero => "All items had weight zero",
        }
    }
}

#[cfg(feature="std")]
impl ::std::error::Error for WeightedError {
    fn description(&self) -> &str {
        self.msg()
    }
    fn cause(&self) -> Option<&::std::error::Error> {
        None
    }
}

impl fmt::Display for WeightedError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.msg())
    }
}
<commit_msg>Add performance documentation for WeightedIndex<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use Rng;
use distributions::Distribution;
use distributions::uniform::{UniformSampler, SampleUniform, SampleBorrow};
use ::core::cmp::PartialOrd;
use core::fmt;

// Note that this whole module is only imported if feature="alloc" is enabled.
#[cfg(not(feature="std"))] use alloc::vec::Vec;

/// A distribution using weighted sampling to pick a discretely selected
/// item.
///
/// Sampling a `WeightedIndex` distribution returns the index of a randomly
/// selected element from the iterator used when the `WeightedIndex` was
/// created. The chance of a given element being picked is proportional to the
/// value of the element. The weights can use any type `X` for which an
/// implementation of [`Uniform<X>`] exists.
///
/// # Performance
///
/// A `WeightedIndex<X>` contains a `Vec<X>` and a [`Uniform<X>`] and so its
/// size is the sum of the size of those objects, possibly plus some alignment.
///
/// Creating a `WeightedIndex<X>` will allocate enough space to hold `N - 1`
/// weights of type `X`, where `N` is the number of weights. However, since
/// `Vec` doesn't guarantee a particular growth strategy, additional memory
/// might be allocated but not used. Since the `WeightedIndex` object also
/// contains, this might cause additional allocations, though for primitive
/// types, ['Uniform<X>`] doesn't allocate any memory.
///
/// Time complexity of sampling from `WeightedIndex` is `O(log N)` where
/// `N` is the number of weights.
///
/// Sampling from `WeightedIndex` will result in a single call to
/// [`Uniform<X>::sample`], which typically will request a single value from
/// the underlying [`RngCore`], though the exact number depends on the
/// implementaiton of [`Uniform<X>::sample`].
///
/// # Example
///
/// ```
/// use rand::prelude::*;
/// use rand::distributions::WeightedIndex;
///
/// let choices = ['a', 'b', 'c'];
/// let weights = [2,   1,   1];
/// let dist = WeightedIndex::new(&weights).unwrap();
/// let mut rng = thread_rng();
/// for _ in 0..100 {
///     // 50% chance to print 'a', 25% chance to print 'b', 25% chance to print 'c'
///     println!("{}", choices[dist.sample(&mut rng)]);
/// }
///
/// let items = [('a', 0), ('b', 3), ('c', 7)];
/// let dist2 = WeightedIndex::new(items.iter().map(|item| item.1)).unwrap();
/// for _ in 0..100 {
///     // 0% chance to print 'a', 30% chance to print 'b', 70% chance to print 'c'
///     println!("{}", items[dist2.sample(&mut rng)].0);
/// }
/// ```
///
/// [`Uniform<X>`]: struct.Uniform.html
/// [`Uniform<X>::sample`]: struct.Uniform.html#method.sample
/// [`RngCore`]: ../trait.RngCore.html
#[derive(Debug, Clone)]
pub struct WeightedIndex<X: SampleUniform + PartialOrd> {
    cumulative_weights: Vec<X>,
    weight_distribution: X::Sampler,
}

impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
    /// Creates a new a `WeightedIndex` [`Distribution`] using the values
    /// in `weights`. The weights can use any type `X` for which an
    /// implementation of [`Uniform<X>`] exists.
    ///
    /// Returns an error if the iterator is empty, if any weight is `< 0`, or
    /// if its total value is 0.
    ///
    /// [`Distribution`]: trait.Distribution.html
    /// [`Uniform<X>`]: struct.Uniform.html
    pub fn new<I>(weights: I) -> Result<WeightedIndex<X>, WeightedError>
        where I: IntoIterator,
              I::Item: SampleBorrow<X>,
              X: for<'a> ::core::ops::AddAssign<&'a X> +
                 Clone +
                 Default {
        let mut iter = weights.into_iter();
        let mut total_weight: X = iter.next()
                                      .ok_or(WeightedError::NoItem)?
                                      .borrow()
                                      .clone();

        let zero = <X as Default>::default();
        if total_weight < zero {
            return Err(WeightedError::NegativeWeight);
        }

        let mut weights = Vec::<X>::with_capacity(iter.size_hint().0);
        for w in iter {
            if *w.borrow() < zero {
                return Err(WeightedError::NegativeWeight);
            }
            weights.push(total_weight.clone());
            total_weight += w.borrow();
        }

        if total_weight == zero {
            return Err(WeightedError::AllWeightsZero);
        }
        let distr = X::Sampler::new(zero, total_weight);

        Ok(WeightedIndex { cumulative_weights: weights, weight_distribution: distr })
    }
}

impl<X> Distribution<usize> for WeightedIndex<X> where
    X: SampleUniform + PartialOrd {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
        use ::core::cmp::Ordering;
        let chosen_weight = self.weight_distribution.sample(rng);
        // Find the first item which has a weight *higher* than the chosen weight.
        self.cumulative_weights.binary_search_by(
            |w| if *w <= chosen_weight { Ordering::Less } else { Ordering::Greater }).unwrap_err()
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_weightedindex() {
        let mut r = ::test::rng(700);
        const N_REPS: u32 = 5000;
        let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7];
        let total_weight = weights.iter().sum::<u32>() as f32;

        let verify = |result: [i32; 14]| {
            for (i, count) in result.iter().enumerate() {
                let exp = (weights[i] * N_REPS) as f32 / total_weight;
                let mut err = (*count as f32 - exp).abs();
                if err != 0.0 {
                    err /= exp;
                }
                assert!(err <= 0.25);
            }
        };

        // WeightedIndex from vec
        let mut chosen = [0i32; 14];
        let distr = WeightedIndex::new(weights.to_vec()).unwrap();
        for _ in 0..N_REPS {
            chosen[distr.sample(&mut r)] += 1;
        }
        verify(chosen);

        // WeightedIndex from slice
        chosen = [0i32; 14];
        let distr = WeightedIndex::new(&weights[..]).unwrap();
        for _ in 0..N_REPS {
            chosen[distr.sample(&mut r)] += 1;
        }
        verify(chosen);

        // WeightedIndex from iterator
        chosen = [0i32; 14];
        let distr = WeightedIndex::new(weights.iter()).unwrap();
        for _ in 0..N_REPS {
            chosen[distr.sample(&mut r)] += 1;
        }
        verify(chosen);

        for _ in 0..5 {
            assert_eq!(WeightedIndex::new(&[0, 1]).unwrap().sample(&mut r), 1);
            assert_eq!(WeightedIndex::new(&[1, 0]).unwrap().sample(&mut r), 0);
            assert_eq!(WeightedIndex::new(&[0, 0, 0, 0, 10, 0]).unwrap().sample(&mut r), 4);
        }

        assert_eq!(WeightedIndex::new(&[10][0..0]).unwrap_err(), WeightedError::NoItem);
        assert_eq!(WeightedIndex::new(&[0]).unwrap_err(), WeightedError::AllWeightsZero);
        assert_eq!(WeightedIndex::new(&[10, 20, -1, 30]).unwrap_err(), WeightedError::NegativeWeight);
        assert_eq!(WeightedIndex::new(&[-10, 20, 1, 30]).unwrap_err(), WeightedError::NegativeWeight);
        assert_eq!(WeightedIndex::new(&[-10]).unwrap_err(), WeightedError::NegativeWeight);
    }
}

/// Error type returned from `WeightedIndex::new`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WeightedError {
    /// The provided iterator contained no items.
    NoItem,

    /// A weight lower than zero was used.
    NegativeWeight,

    /// All items in the provided iterator had a weight of zero.
    AllWeightsZero,
}

impl WeightedError {
    fn msg(&self) -> &str {
        match *self {
            WeightedError::NoItem => "No items found",
            WeightedError::NegativeWeight => "Item has negative weight",
            WeightedError::AllWeightsZero => "All items had weight zero",
        }
    }
}

#[cfg(feature="std")]
impl ::std::error::Error for WeightedError {
    fn description(&self) -> &str {
        self.msg()
    }
    fn cause(&self) -> Option<&::std::error::Error> {
        None
    }
}

impl fmt::Display for WeightedError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.msg())
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Write};

use super::{CountedList, CountedListWriter, CountedWriter, Deserialize, Error, Serialize, VarInt32, VarUint32, VarUint7};

const FUNCTION_INDEX_LEB: u8 = 0;
const TABLE_INDEX_SLEB: u8 = 1;
const TABLE_INDEX_I32: u8 = 2;
const MEMORY_ADDR_LEB: u8 = 3;
const MEMORY_ADDR_SLEB: u8 = 4;
const MEMORY_ADDR_I32: u8 = 5;
const TYPE_INDEX_LEB: u8 = 6;
const GLOBAL_INDEX_LEB: u8 = 7;

/// Relocation information.
#[derive(Clone, Debug)]
pub struct RelocSection {
	/// Name of this section.
	name: String,

	/// ID of the section containing the relocations described in this section.
	section_id: u32,

	/// Name of the section containing the relocations described in this section. Only set if section_id is 0.
	relocation_section_name: Option<String>,

	/// Relocation entries.
	entries: Vec<RelocationEntry>,
}

impl RelocSection {
	/// Name of this section.
	pub fn name(&self) -> &str {
		&self.name
	}

	/// Name of this section (mutable).
	pub fn name_mut(&mut self) -> &mut String {
		&mut self.name
	}

	/// ID of the section containing the relocations described in this section.
	pub fn section_id(&self) -> u32 {
		self.section_id
	}

	/// ID of the section containing the relocations described in this section (mutable).
	pub fn section_id_mut(&mut self) -> &mut u32 {
		&mut self.section_id
	}

	/// Name of the section containing the relocations described in this section.
	pub fn relocation_section_name(&self) -> Option<&str> {
		self.relocation_section_name.as_ref().map(String::as_str)
	}

	/// Name of the section containing the relocations described in this section (mutable).
	pub fn relocation_section_name_mut(&mut self) -> &mut Option<String> {
		&mut self.relocation_section_name
	}

	/// List of relocation entries.
	pub fn entries(&self) -> &[RelocationEntry] {
		&self.entries
	}

	/// List of relocation entries (mutable).
	pub fn entries_mut(&mut self) -> &mut Vec<RelocationEntry> {
		&mut self.entries
	}
}

impl RelocSection {
	pub fn deserialize<R: Read>(
		name: String,
		rdr: &mut R,
	) -> Result<Self, Error> {
		let section_id = VarUint32::deserialize(rdr)?.into();

		let relocation_section_name =
			if section_id == 0 {
				Some(String::deserialize(rdr)?)
			}
			else {
				None
			};

		let entries = CountedList::deserialize(rdr)?.into_inner();

		Ok(RelocSection {
			name,
			section_id,
			relocation_section_name,
			entries,
		})
	}
}

impl Serialize for RelocSection {
	type Error = Error;

	fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
		let mut counted_writer = CountedWriter::new(wtr);

		self.name.serialize(&mut counted_writer)?;

		VarUint32::from(self.section_id).serialize(&mut counted_writer)?;

		if let Some(relocation_section_name) = self.relocation_section_name {
			relocation_section_name.serialize(&mut counted_writer)?;
		}

		let counted_list = CountedListWriter(self.entries.len(), self.entries.into_iter());
		counted_list.serialize(&mut counted_writer)?;

		counted_writer.done()?;

		Ok(())
	}
}

/// Relocation entry.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum RelocationEntry {
	/// Function index.
	FunctionIndexLeb {
		/// Offset of the value to rewrite.
		offset: u32,

		/// Index of the function symbol in the symbol table.
		index: u32,
	},

	/// Function table index.
	TableIndexSleb {
		offset: u32,
		index: u32,
	},

	/// Function table index.
	TableIndexI32 {
		offset: u32,
		index: u32,
	},

	/// Linear memory index.
	MemoryAddressLeb {
		offset: u32,
		index: u32,
		addend: i32,
	},

	/// Linear memory index.
	MemoryAddressSleb {
		offset: u32,
		index: u32,
		addend: i32,
	},

	/// Linear memory index.
	MemoryAddressI32 {
		offset: u32,
		index: u32,
		addend: i32,
	},

	/// Type table index.
	TypeIndexLeb {
		offset: u32,
		index: u32,
	},

	/// Global index.
	GlobalIndexLeb {
		offset: u32,
		index: u32,
	},
}

impl Deserialize for RelocationEntry {
	type Error = Error;

	fn deserialize<R: Read>(rdr: &mut R) -> Result<Self, Self::Error> {
		match VarUint7::deserialize(rdr)?.into() {
			FUNCTION_INDEX_LEB => Ok(RelocationEntry::FunctionIndexLeb {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
			}),

			TABLE_INDEX_SLEB => Ok(RelocationEntry::TableIndexSleb {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
			}),

			TABLE_INDEX_I32 => Ok(RelocationEntry::TableIndexI32 {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
			}),

			MEMORY_ADDR_LEB => Ok(RelocationEntry::MemoryAddressLeb {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
				addend: VarInt32::deserialize(rdr)?.into(),
			}),

			MEMORY_ADDR_SLEB => Ok(RelocationEntry::MemoryAddressSleb {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
				addend: VarInt32::deserialize(rdr)?.into(),
			}),

			MEMORY_ADDR_I32 => Ok(RelocationEntry::MemoryAddressI32 {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
				addend: VarInt32::deserialize(rdr)?.into(),
			}),

			TYPE_INDEX_LEB => Ok(RelocationEntry::TypeIndexLeb {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
			}),

			GLOBAL_INDEX_LEB => Ok(RelocationEntry::GlobalIndexLeb {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
			}),

			entry_type => Err(Error::UnknownValueType(entry_type as i8)),
		}
	}
}

impl Serialize for RelocationEntry {
	type Error = Error;

	fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
		match self {
			RelocationEntry::FunctionIndexLeb { offset, index } => {
				VarUint7::from(FUNCTION_INDEX_LEB).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
			},

			RelocationEntry::TableIndexSleb { offset, index } => {
				VarUint7::from(TABLE_INDEX_SLEB).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
			},

			RelocationEntry::TableIndexI32 { offset, index } => {
				VarUint7::from(TABLE_INDEX_I32).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
			},

			RelocationEntry::MemoryAddressLeb { offset, index, addend } => {
				VarUint7::from(MEMORY_ADDR_LEB).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
				VarInt32::from(addend).serialize(wtr)?;
			},

			RelocationEntry::MemoryAddressSleb { offset, index, addend } => {
				VarUint7::from(MEMORY_ADDR_SLEB).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
				VarInt32::from(addend).serialize(wtr)?;
			},

			RelocationEntry::MemoryAddressI32 { offset, index, addend } => {
				VarUint7::from(MEMORY_ADDR_I32).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
				VarInt32::from(addend).serialize(wtr)?;
			},

			RelocationEntry::TypeIndexLeb { offset, index } => {
				VarUint7::from(TYPE_INDEX_LEB).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
			},

			RelocationEntry::GlobalIndexLeb { offset, index } => {
				VarUint7::from(GLOBAL_INDEX_LEB).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
			},
		}

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	use super::super::{Section, deserialize_file};
	use super::RelocationEntry;

	#[test]
	fn reloc_section() {
		let module =
			deserialize_file("./res/cases/v1/relocatable.wasm").expect("Module should be deserialized")
			.parse_reloc().expect("Reloc section should be deserialized");
		let mut found = false;
		for section in module.sections() {
			match *section {
				Section::Reloc(ref reloc_section) => {
					assert_eq!(vec![
						RelocationEntry::MemoryAddressSleb { offset: 4, index: 0, addend: 0 },
						RelocationEntry::FunctionIndexLeb { offset: 12, index: 0 },
					], reloc_section.entries());
					found = true
				},
				_ => { }
			}
		}
		assert!(found, "There should be a reloc section in relocatable.wasm");
	}
}
<commit_msg>Added more missing doc comments.<commit_after>use std::io::{Read, Write};

use super::{CountedList, CountedListWriter, CountedWriter, Deserialize, Error, Serialize, VarInt32, VarUint32, VarUint7};

const FUNCTION_INDEX_LEB: u8 = 0;
const TABLE_INDEX_SLEB: u8 = 1;
const TABLE_INDEX_I32: u8 = 2;
const MEMORY_ADDR_LEB: u8 = 3;
const MEMORY_ADDR_SLEB: u8 = 4;
const MEMORY_ADDR_I32: u8 = 5;
const TYPE_INDEX_LEB: u8 = 6;
const GLOBAL_INDEX_LEB: u8 = 7;

/// Relocation information.
#[derive(Clone, Debug)]
pub struct RelocSection {
	/// Name of this section.
	name: String,

	/// ID of the section containing the relocations described in this section.
	section_id: u32,

	/// Name of the section containing the relocations described in this section. Only set if section_id is 0.
	relocation_section_name: Option<String>,

	/// Relocation entries.
	entries: Vec<RelocationEntry>,
}

impl RelocSection {
	/// Name of this section.
	pub fn name(&self) -> &str {
		&self.name
	}

	/// Name of this section (mutable).
	pub fn name_mut(&mut self) -> &mut String {
		&mut self.name
	}

	/// ID of the section containing the relocations described in this section.
	pub fn section_id(&self) -> u32 {
		self.section_id
	}

	/// ID of the section containing the relocations described in this section (mutable).
	pub fn section_id_mut(&mut self) -> &mut u32 {
		&mut self.section_id
	}

	/// Name of the section containing the relocations described in this section.
	pub fn relocation_section_name(&self) -> Option<&str> {
		self.relocation_section_name.as_ref().map(String::as_str)
	}

	/// Name of the section containing the relocations described in this section (mutable).
	pub fn relocation_section_name_mut(&mut self) -> &mut Option<String> {
		&mut self.relocation_section_name
	}

	/// List of relocation entries.
	pub fn entries(&self) -> &[RelocationEntry] {
		&self.entries
	}

	/// List of relocation entries (mutable).
	pub fn entries_mut(&mut self) -> &mut Vec<RelocationEntry> {
		&mut self.entries
	}
}

impl RelocSection {
	pub fn deserialize<R: Read>(
		name: String,
		rdr: &mut R,
	) -> Result<Self, Error> {
		let section_id = VarUint32::deserialize(rdr)?.into();

		let relocation_section_name =
			if section_id == 0 {
				Some(String::deserialize(rdr)?)
			}
			else {
				None
			};

		let entries = CountedList::deserialize(rdr)?.into_inner();

		Ok(RelocSection {
			name,
			section_id,
			relocation_section_name,
			entries,
		})
	}
}

impl Serialize for RelocSection {
	type Error = Error;

	fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
		let mut counted_writer = CountedWriter::new(wtr);

		self.name.serialize(&mut counted_writer)?;

		VarUint32::from(self.section_id).serialize(&mut counted_writer)?;

		if let Some(relocation_section_name) = self.relocation_section_name {
			relocation_section_name.serialize(&mut counted_writer)?;
		}

		let counted_list = CountedListWriter(self.entries.len(), self.entries.into_iter());
		counted_list.serialize(&mut counted_writer)?;

		counted_writer.done()?;

		Ok(())
	}
}

/// Relocation entry.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum RelocationEntry {
	/// Function index.
	FunctionIndexLeb {
		/// Offset of the value to rewrite.
		offset: u32,

		/// Index of the function symbol in the symbol table.
		index: u32,
	},

	/// Function table index.
	TableIndexSleb {
		/// Offset of the value to rewrite.
		offset: u32,

		/// Index of the function symbol in the symbol table.
		index: u32,
	},

	/// Function table index.
	TableIndexI32 {
		/// Offset of the value to rewrite.
		offset: u32,

		/// Index of the function symbol in the symbol table.
		index: u32,
	},

	/// Linear memory index.
	MemoryAddressLeb {
		/// Offset of the value to rewrite.
		offset: u32,

		/// Index of the data symbol in the symbol table.
		index: u32,

		/// Addend to add to the address.
		addend: i32,
	},

	/// Linear memory index.
	MemoryAddressSleb {
		/// Offset of the value to rewrite.
		offset: u32,

		/// Index of the data symbol in the symbol table.
		index: u32,

		/// Addend to add to the address.
		addend: i32,
	},

	/// Linear memory index.
	MemoryAddressI32 {
		/// Offset of the value to rewrite.
		offset: u32,

		/// Index of the data symbol in the symbol table.
		index: u32,

		/// Addend to add to the address.
		addend: i32,
	},

	/// Type table index.
	TypeIndexLeb {
		/// Offset of the value to rewrite.
		offset: u32,

		/// Index of the type used.
		index: u32,
	},

	/// Global index.
	GlobalIndexLeb {
		/// Offset of the value to rewrite.
		offset: u32,

		/// Index of the global symbol in the symbol table.
		index: u32,
	},
}

impl Deserialize for RelocationEntry {
	type Error = Error;

	fn deserialize<R: Read>(rdr: &mut R) -> Result<Self, Self::Error> {
		match VarUint7::deserialize(rdr)?.into() {
			FUNCTION_INDEX_LEB => Ok(RelocationEntry::FunctionIndexLeb {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
			}),

			TABLE_INDEX_SLEB => Ok(RelocationEntry::TableIndexSleb {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
			}),

			TABLE_INDEX_I32 => Ok(RelocationEntry::TableIndexI32 {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
			}),

			MEMORY_ADDR_LEB => Ok(RelocationEntry::MemoryAddressLeb {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
				addend: VarInt32::deserialize(rdr)?.into(),
			}),

			MEMORY_ADDR_SLEB => Ok(RelocationEntry::MemoryAddressSleb {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
				addend: VarInt32::deserialize(rdr)?.into(),
			}),

			MEMORY_ADDR_I32 => Ok(RelocationEntry::MemoryAddressI32 {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
				addend: VarInt32::deserialize(rdr)?.into(),
			}),

			TYPE_INDEX_LEB => Ok(RelocationEntry::TypeIndexLeb {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
			}),

			GLOBAL_INDEX_LEB => Ok(RelocationEntry::GlobalIndexLeb {
				offset: VarUint32::deserialize(rdr)?.into(),
				index: VarUint32::deserialize(rdr)?.into(),
			}),

			entry_type => Err(Error::UnknownValueType(entry_type as i8)),
		}
	}
}

impl Serialize for RelocationEntry {
	type Error = Error;

	fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
		match self {
			RelocationEntry::FunctionIndexLeb { offset, index } => {
				VarUint7::from(FUNCTION_INDEX_LEB).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
			},

			RelocationEntry::TableIndexSleb { offset, index } => {
				VarUint7::from(TABLE_INDEX_SLEB).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
			},

			RelocationEntry::TableIndexI32 { offset, index } => {
				VarUint7::from(TABLE_INDEX_I32).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
			},

			RelocationEntry::MemoryAddressLeb { offset, index, addend } => {
				VarUint7::from(MEMORY_ADDR_LEB).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
				VarInt32::from(addend).serialize(wtr)?;
			},

			RelocationEntry::MemoryAddressSleb { offset, index, addend } => {
				VarUint7::from(MEMORY_ADDR_SLEB).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
				VarInt32::from(addend).serialize(wtr)?;
			},

			RelocationEntry::MemoryAddressI32 { offset, index, addend } => {
				VarUint7::from(MEMORY_ADDR_I32).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
				VarInt32::from(addend).serialize(wtr)?;
			},

			RelocationEntry::TypeIndexLeb { offset, index } => {
				VarUint7::from(TYPE_INDEX_LEB).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
			},

			RelocationEntry::GlobalIndexLeb { offset, index } => {
				VarUint7::from(GLOBAL_INDEX_LEB).serialize(wtr)?;
				VarUint32::from(offset).serialize(wtr)?;
				VarUint32::from(index).serialize(wtr)?;
			},
		}

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	use super::super::{Section, deserialize_file};
	use super::RelocationEntry;

	#[test]
	fn reloc_section() {
		let module =
			deserialize_file("./res/cases/v1/relocatable.wasm").expect("Module should be deserialized")
			.parse_reloc().expect("Reloc section should be deserialized");
		let mut found = false;
		for section in module.sections() {
			match *section {
				Section::Reloc(ref reloc_section) => {
					assert_eq!(vec![
						RelocationEntry::MemoryAddressSleb { offset: 4, index: 0, addend: 0 },
						RelocationEntry::FunctionIndexLeb { offset: 12, index: 0 },
					], reloc_section.entries());
					found = true
				},
				_ => { }
			}
		}
		assert!(found, "There should be a reloc section in relocatable.wasm");
	}
}
<|endoftext|>


<commit_before><commit_msg>Fix error reporting for braceless Unicode escapes<commit_after><|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// TODO(antiphoton) No longer allow unused_unit when a new version wasm_bindgen is released with
// https://github.com/rustwasm/wasm-bindgen/pull/2778
#![allow(clippy::unused_unit)]

use crate::headers::AcceptFilter;
use crate::http::HttpResponse;
use crate::process_html::ProcessHtmlOption;
use crate::utils::to_js_error;
use crate::SxgWorker;
use anyhow::Result;
use js_sys::Function as JsFunction;
use js_sys::Promise as JsPromise;
use js_sys::Uint8Array;
use std::sync::Arc;
use wasm_bindgen::prelude::{wasm_bindgen, JsValue};
use wasm_bindgen_futures::future_to_promise;

#[wasm_bindgen]
pub struct WasmWorker(Arc<SxgWorker>);

#[wasm_bindgen]
extern "C" {
    pub type CreateSignedExchangedOptions;
    #[wasm_bindgen(method, getter, js_name = "fallbackUrl")]
    fn fallback_url(this: &CreateSignedExchangedOptions) -> String;
    #[wasm_bindgen(method, getter, js_name = "certOrigin")]
    fn cert_origin(this: &CreateSignedExchangedOptions) -> String;
    #[wasm_bindgen(method, getter, js_name = "statusCode")]
    fn status_code(this: &CreateSignedExchangedOptions) -> u16;
    #[wasm_bindgen(method, getter, js_name = "payloadHeaders")]
    fn payload_headers(this: &CreateSignedExchangedOptions) -> JsValue;
    #[wasm_bindgen(method, getter, js_name = "payloadBody")]
    fn payload_body(this: &CreateSignedExchangedOptions) -> Vec<u8>;
    #[wasm_bindgen(method, getter, js_name = "skipProcessLink")]
    fn skip_process_link(this: &CreateSignedExchangedOptions) -> bool;
    #[wasm_bindgen(method, getter, js_name = "nowInSeconds")]
    fn now_in_seconds(this: &CreateSignedExchangedOptions) -> u32;
    #[wasm_bindgen(method, getter, js_name = "signer")]
    fn signer(this: &CreateSignedExchangedOptions) -> JsFunction;
    #[wasm_bindgen(method, getter, js_name = "subresourceFetcher")]
    fn subresource_fetcher(this: &CreateSignedExchangedOptions) -> JsFunction;
    #[wasm_bindgen(method, getter, js_name = "headerIntegrityGet")]
    fn header_integrity_get(this: &CreateSignedExchangedOptions) -> JsFunction;
    #[wasm_bindgen(method, getter, js_name = "headerIntegrityPut")]
    fn header_integrity_put(this: &CreateSignedExchangedOptions) -> JsFunction;
}

#[wasm_bindgen]
impl WasmWorker {
    #[wasm_bindgen(constructor)]
    pub fn new(config_yaml: &str, cert_pem: &str, issuer_pem: &str) -> Result<WasmWorker, JsValue> {
        let sxg_worker = SxgWorker::new(config_yaml, cert_pem, issuer_pem).map_err(to_js_error)?;
        Ok(WasmWorker(Arc::new(sxg_worker)))
    }
    #[wasm_bindgen(js_name=fetchOcspFromCa)]
    pub fn fetch_ocsp_from_ca(&self, fetcher: JsFunction) -> JsPromise {
        let worker = self.0.clone();
        future_to_promise(async move {
            let fetcher = crate::fetcher::js_fetcher::JsFetcher::new(fetcher);
            let response = worker.fetch_ocsp_from_ca(fetcher).await;
            let ocsp = Uint8Array::from(response.as_slice());
            Ok(JsValue::from(ocsp))
        })
    }
    #[wasm_bindgen(js_name=servePresetContent)]
    pub fn serve_preset_content(
        &self,
        req_url: &str,
        ocsp_base64: &str,
    ) -> Result<JsValue, JsValue> {
        let ocsp_der = ::base64::decode(ocsp_base64).unwrap();
        Ok(self
            .0
            .serve_preset_content(req_url, &ocsp_der)
            .map_or(JsValue::UNDEFINED, |preset_content| {
                JsValue::from_serde(&preset_content).unwrap()
            }))
    }
    #[wasm_bindgen(js_name=shouldRespondDebugInfo)]
    pub fn should_respond_debug_info(&self) -> Result<bool, JsValue> {
        Ok(self.0.should_respond_debug_info())
    }

    #[wasm_bindgen(js_name=createRequestHeaders)]
    pub fn create_request_headers(
        &self,
        accept_filter: JsValue,
        requestor_headers: JsValue,
    ) -> Result<JsValue, JsValue> {
        let fields = requestor_headers.into_serde().unwrap();
        let accept_filter: AcceptFilter = accept_filter.into_serde().unwrap();
        let result = self.0.transform_request_headers(fields, accept_filter);
        match result {
            Ok(fields) => Ok(JsValue::from_serde(&fields).unwrap()),
            Err(err) => Err(to_js_error(err)),
        }
    }
    #[wasm_bindgen(js_name=validatePayloadHeaders)]
    pub fn validate_payload_headers(&self, fields: JsValue) -> Result<(), JsValue> {
        let fields: Vec<(String, String)> = fields.into_serde().map_err(to_js_error)?;
        self.0
            .transform_payload_headers(fields)
            .map_err(to_js_error)?;
        Ok(())
    }
    #[wasm_bindgen(js_name=processHtml)]
    pub fn process_html(&self, input: JsValue, option: JsValue) -> Result<JsValue, JsValue> {
        let input: HttpResponse = input.into_serde().map_err(to_js_error)?;
        let option: ProcessHtmlOption = option.into_serde().map_err(to_js_error)?;
        let output = self.0.process_html(input, option).map_err(to_js_error)?;
        JsValue::from_serde(&output).map_err(to_js_error)
    }
    #[wasm_bindgen(js_name=createSignedExchange)]
    pub fn create_signed_exchange(&self, options: CreateSignedExchangedOptions) -> JsPromise {
        let worker = self.0.clone();
        future_to_promise(async move {
            let payload_headers: Vec<(String, String)> = options
                .payload_headers()
                .into_serde()
                .map_err(to_js_error)?;
            let payload_headers = worker
                .transform_payload_headers(payload_headers)
                .map_err(to_js_error)?;
            let signer = crate::signature::js_signer::JsSigner::from_raw_signer(options.signer());
            let subresource_fetcher =
                crate::fetcher::js_fetcher::JsFetcher::new(options.subresource_fetcher());
            let header_integrity_cache = crate::http_cache::js_http_cache::JsHttpCache {
                get: options.header_integrity_get(),
                put: options.header_integrity_put(),
            };
            let sxg: HttpResponse = worker
                .create_signed_exchange(crate::CreateSignedExchangeParams {
                    fallback_url: &options.fallback_url(),
                    cert_origin: &options.cert_origin(),
                    now: std::time::UNIX_EPOCH
                        + std::time::Duration::from_secs(options.now_in_seconds() as u64),
                    payload_body: &options.payload_body(),
                    payload_headers,
                    signer,
                    status_code: options.status_code(),
                    subresource_fetcher,
                    header_integrity_cache,
                    skip_process_link: options.skip_process_link(),
                })
                .await
                .map_err(to_js_error)?;
            Ok(JsValue::from_serde(&sxg).unwrap())
        })
    }
}
<commit_msg>No longer allow unused unit (#241)<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::headers::AcceptFilter;
use crate::http::HttpResponse;
use crate::process_html::ProcessHtmlOption;
use crate::utils::to_js_error;
use crate::SxgWorker;
use anyhow::Result;
use js_sys::Function as JsFunction;
use js_sys::Promise as JsPromise;
use js_sys::Uint8Array;
use std::sync::Arc;
use wasm_bindgen::prelude::{wasm_bindgen, JsValue};
use wasm_bindgen_futures::future_to_promise;

#[wasm_bindgen]
pub struct WasmWorker(Arc<SxgWorker>);

#[wasm_bindgen]
extern "C" {
    pub type CreateSignedExchangedOptions;
    #[wasm_bindgen(method, getter, js_name = "fallbackUrl")]
    fn fallback_url(this: &CreateSignedExchangedOptions) -> String;
    #[wasm_bindgen(method, getter, js_name = "certOrigin")]
    fn cert_origin(this: &CreateSignedExchangedOptions) -> String;
    #[wasm_bindgen(method, getter, js_name = "statusCode")]
    fn status_code(this: &CreateSignedExchangedOptions) -> u16;
    #[wasm_bindgen(method, getter, js_name = "payloadHeaders")]
    fn payload_headers(this: &CreateSignedExchangedOptions) -> JsValue;
    #[wasm_bindgen(method, getter, js_name = "payloadBody")]
    fn payload_body(this: &CreateSignedExchangedOptions) -> Vec<u8>;
    #[wasm_bindgen(method, getter, js_name = "skipProcessLink")]
    fn skip_process_link(this: &CreateSignedExchangedOptions) -> bool;
    #[wasm_bindgen(method, getter, js_name = "nowInSeconds")]
    fn now_in_seconds(this: &CreateSignedExchangedOptions) -> u32;
    #[wasm_bindgen(method, getter, js_name = "signer")]
    fn signer(this: &CreateSignedExchangedOptions) -> JsFunction;
    #[wasm_bindgen(method, getter, js_name = "subresourceFetcher")]
    fn subresource_fetcher(this: &CreateSignedExchangedOptions) -> JsFunction;
    #[wasm_bindgen(method, getter, js_name = "headerIntegrityGet")]
    fn header_integrity_get(this: &CreateSignedExchangedOptions) -> JsFunction;
    #[wasm_bindgen(method, getter, js_name = "headerIntegrityPut")]
    fn header_integrity_put(this: &CreateSignedExchangedOptions) -> JsFunction;
}

#[wasm_bindgen]
impl WasmWorker {
    #[wasm_bindgen(constructor)]
    pub fn new(config_yaml: &str, cert_pem: &str, issuer_pem: &str) -> Result<WasmWorker, JsValue> {
        let sxg_worker = SxgWorker::new(config_yaml, cert_pem, issuer_pem).map_err(to_js_error)?;
        Ok(WasmWorker(Arc::new(sxg_worker)))
    }
    #[wasm_bindgen(js_name=fetchOcspFromCa)]
    pub fn fetch_ocsp_from_ca(&self, fetcher: JsFunction) -> JsPromise {
        let worker = self.0.clone();
        future_to_promise(async move {
            let fetcher = crate::fetcher::js_fetcher::JsFetcher::new(fetcher);
            let response = worker.fetch_ocsp_from_ca(fetcher).await;
            let ocsp = Uint8Array::from(response.as_slice());
            Ok(JsValue::from(ocsp))
        })
    }
    #[wasm_bindgen(js_name=servePresetContent)]
    pub fn serve_preset_content(
        &self,
        req_url: &str,
        ocsp_base64: &str,
    ) -> Result<JsValue, JsValue> {
        let ocsp_der = ::base64::decode(ocsp_base64).unwrap();
        Ok(self
            .0
            .serve_preset_content(req_url, &ocsp_der)
            .map_or(JsValue::UNDEFINED, |preset_content| {
                JsValue::from_serde(&preset_content).unwrap()
            }))
    }
    #[wasm_bindgen(js_name=shouldRespondDebugInfo)]
    pub fn should_respond_debug_info(&self) -> Result<bool, JsValue> {
        Ok(self.0.should_respond_debug_info())
    }

    #[wasm_bindgen(js_name=createRequestHeaders)]
    pub fn create_request_headers(
        &self,
        accept_filter: JsValue,
        requestor_headers: JsValue,
    ) -> Result<JsValue, JsValue> {
        let fields = requestor_headers.into_serde().unwrap();
        let accept_filter: AcceptFilter = accept_filter.into_serde().unwrap();
        let result = self.0.transform_request_headers(fields, accept_filter);
        match result {
            Ok(fields) => Ok(JsValue::from_serde(&fields).unwrap()),
            Err(err) => Err(to_js_error(err)),
        }
    }
    #[wasm_bindgen(js_name=validatePayloadHeaders)]
    pub fn validate_payload_headers(&self, fields: JsValue) -> Result<(), JsValue> {
        let fields: Vec<(String, String)> = fields.into_serde().map_err(to_js_error)?;
        self.0
            .transform_payload_headers(fields)
            .map_err(to_js_error)?;
        Ok(())
    }
    #[wasm_bindgen(js_name=processHtml)]
    pub fn process_html(&self, input: JsValue, option: JsValue) -> Result<JsValue, JsValue> {
        let input: HttpResponse = input.into_serde().map_err(to_js_error)?;
        let option: ProcessHtmlOption = option.into_serde().map_err(to_js_error)?;
        let output = self.0.process_html(input, option).map_err(to_js_error)?;
        JsValue::from_serde(&output).map_err(to_js_error)
    }
    #[wasm_bindgen(js_name=createSignedExchange)]
    pub fn create_signed_exchange(&self, options: CreateSignedExchangedOptions) -> JsPromise {
        let worker = self.0.clone();
        future_to_promise(async move {
            let payload_headers: Vec<(String, String)> = options
                .payload_headers()
                .into_serde()
                .map_err(to_js_error)?;
            let payload_headers = worker
                .transform_payload_headers(payload_headers)
                .map_err(to_js_error)?;
            let signer = crate::signature::js_signer::JsSigner::from_raw_signer(options.signer());
            let subresource_fetcher =
                crate::fetcher::js_fetcher::JsFetcher::new(options.subresource_fetcher());
            let header_integrity_cache = crate::http_cache::js_http_cache::JsHttpCache {
                get: options.header_integrity_get(),
                put: options.header_integrity_put(),
            };
            let sxg: HttpResponse = worker
                .create_signed_exchange(crate::CreateSignedExchangeParams {
                    fallback_url: &options.fallback_url(),
                    cert_origin: &options.cert_origin(),
                    now: std::time::UNIX_EPOCH
                        + std::time::Duration::from_secs(options.now_in_seconds() as u64),
                    payload_body: &options.payload_body(),
                    payload_headers,
                    signer,
                    status_code: options.status_code(),
                    subresource_fetcher,
                    header_integrity_cache,
                    skip_process_link: options.skip_process_link(),
                })
                .await
                .map_err(to_js_error)?;
            Ok(JsValue::from_serde(&sxg).unwrap())
        })
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use serenity::model::id::GuildId;
use sqlx::{Error, PgPool};
use std::time::Duration;
use tracing::warn;

const DEFAULT_WELCOME_MESSAGE: &str = "Welcome to $guild $user!";

pub const SILENT_COMMANDS_MOD_ONLY: i32 = 0;
pub const SILENT_COMMANDS_ALL: i32 = 1;
pub const WORD_FILTER_LEVEL_LOW: i32 = 0;
pub const WORD_FILTER_LEVEL_HIGH: i32 = 1;
pub const ACTION_NOTHING: i32 = 0;
pub const ACTION_WARN: i32 = 1;
pub const ACTION_MUTE: i32 = 2;
pub const ACTION_KICK: i32 = 3;
pub const ACTION_BAN: i32 = 4;
pub const ACTION_SOFTBAN: i32 = 5;
pub const ACTION_HARDBAN: i32 = 6;
pub const DURATION_TYPE_SECONDS: i32 = 0;
pub const DURATION_TYPE_MINUTES: i32 = 1;
pub const DURATION_TYPE_HOURS: i32 = 2;
pub const DURATION_TYPE_DAYS: i32 = 3;
pub const PRIVACY_EVERYONE: i32 = 0;
pub const PRIVACY_STAFF_ONLY: i32 = 1;
pub const PRIVACY_ADMIN_ONLY: i32 = 2;

pub fn get_action_duration_for_auto_mod_action(
    kind: i32,
    duration_type: i32,
    duration: i32,
) -> Option<Duration> {
    if kind == ACTION_BAN || kind == ACTION_MUTE {
        if duration == 0 {
            None
        } else {
            Some(Duration::from_secs(if duration == DURATION_TYPE_SECONDS {
                duration
            } else if duration == DURATION_TYPE_MINUTES {
                duration * 60
            } else if duration == DURATION_TYPE_HOURS {
                duration * 60 * 60
            } else if duration == DURATION_TYPE_DAYS {
                duration * 60 * 60 * 24
            } else {
                warn!(
                    kind = kind,
                    duration_type = duration_type,
                    "invalid state for mod action duration type!"
                );
                return None;
            } as u64))
        }
    } else {
        None
    }
}

#[derive(sqlx::FromRow)]
pub struct Setting {
    pub guild_id: i64,
    pub mod_log: bool,
    pub mod_log_channel_id: i64,
    pub holding_room: bool,
    pub holding_room_role_id: Option<i64>,
    pub holding_room_minutes: i32,
    pub invite_link_remover: bool,
    pub welcome_message: bool,
    pub message: String,
    pub welcome_message_channel_id: i64,
    pub prefix: String,        // deprecated
    pub silent_commands: bool, // deprecated
    pub no_space_prefix: bool, // deprecated
    pub statistics: bool,      // deprecated
    pub join_captcha: bool,
    pub silent_commands_level: i32,            // deprecated
    pub mod_action_confirmation_message: bool, // deprecated
    pub word_filter: bool,
    pub word_filter_blocklist: Option<String>,
    pub word_filter_level: i32,
    pub word_filter_action: i32,
    pub word_filter_action_duration: i32,
    pub word_filter_action_duration_type: i32,
    pub invite_link_remover_action: i32,
    pub invite_link_remover_action_duration: i32,
    pub invite_link_remover_action_duration_type: i32,
    pub privacy_settings: i32,
    pub privacy_mod_log: i32,
    pub softban_threshold: i32,
    pub softban_action: i32,
    pub softban_action_duration: i32,
    pub softban_action_duration_type: i32,
    pub kick_threshold: i32,
    pub kick_action: i32,
    pub kick_action_duration: i32,
    pub kick_action_duration_type: i32,
    pub mute_threshold: i32,
    pub mute_action: i32,
    pub mute_action_duration: i32,
    pub mute_action_duration_type: i32,
    pub warn_threshold: i32,
    pub warn_action: i32,
    pub warn_action_duration: i32,
    pub warn_action_duration_type: i32,
    pub mods_can_edit_tags: bool,
}

impl Setting {
    pub fn default(guild_id: GuildId) -> Self {
        Setting {
            guild_id: guild_id.0 as i64,
            mod_log: false,
            mod_log_channel_id: 0,
            holding_room: false,
            holding_room_role_id: Option::None,
            holding_room_minutes: 3,
            invite_link_remover: false,
            welcome_message: false,
            message: DEFAULT_WELCOME_MESSAGE.into(),
            welcome_message_channel_id: 0,
            prefix: String::new(),
            silent_commands: false,
            no_space_prefix: false,
            statistics: false,
            join_captcha: false,
            silent_commands_level: SILENT_COMMANDS_MOD_ONLY,
            mod_action_confirmation_message: true,
            word_filter: false,
            word_filter_blocklist: Option::None,
            word_filter_level: WORD_FILTER_LEVEL_LOW,
            word_filter_action: ACTION_WARN,
            word_filter_action_duration: 0,
            word_filter_action_duration_type: DURATION_TYPE_MINUTES,
            invite_link_remover_action: ACTION_WARN,
            invite_link_remover_action_duration: 0,
            invite_link_remover_action_duration_type: DURATION_TYPE_MINUTES,
            privacy_settings: PRIVACY_EVERYONE,
            privacy_mod_log: PRIVACY_EVERYONE,
            softban_threshold: 0,
            softban_action: ACTION_NOTHING,
            softban_action_duration: 0,
            softban_action_duration_type: DURATION_TYPE_MINUTES,
            kick_threshold: 0,
            kick_action: ACTION_NOTHING,
            kick_action_duration: 0,
            kick_action_duration_type: DURATION_TYPE_MINUTES,
            mute_threshold: 0,
            mute_action: ACTION_NOTHING,
            mute_action_duration: 0,
            mute_action_duration_type: DURATION_TYPE_MINUTES,
            warn_threshold: 0,
            warn_action: ACTION_NOTHING,
            warn_action_duration: 0,
            warn_action_duration_type: DURATION_TYPE_MINUTES,
            mods_can_edit_tags: false,
        }
    }
}

pub struct SettingsRepository(pub Arc<PgPool>);

impl SettingsRepository {
    pub async fn initialize(&self) -> Result<(), Error> {
        sqlx::query(include_str!("sql/settings/create_table.sql"))
            .execute(&*self.0)
            .await?;
        Ok(())
    }

    pub async fn fetch_setting(&self, guild_id: i64) -> Result<Option<Setting>, Error> {
        Ok(
            sqlx::query_as::<_, Setting>(include_str!("sql/settings/select_guild_setting.sql"))
                .bind(guild_id)
                .fetch_optional(&*self.0)
                .await?,
        )
    }

    pub async fn insert_setting(&self, setting: Setting) -> Result<Setting, Error> {
        Ok(
            sqlx::query_as::<_, Setting>(include_str!("sql/settings/insert_entity.sql"))
                .bind(setting.guild_id)
                .bind(setting.mod_log)
                .bind(setting.mod_log_channel_id)
                .bind(setting.holding_room)
                .bind(setting.holding_room_role_id)
                .bind(setting.holding_room_minutes)
                .bind(setting.invite_link_remover)
                .bind(setting.welcome_message)
                .bind(setting.message)
                .bind(setting.welcome_message_channel_id)
                .bind(setting.prefix)
                .bind(setting.silent_commands)
                .bind(setting.no_space_prefix)
                .bind(setting.statistics)
                .bind(setting.join_captcha)
                .bind(setting.silent_commands_level)
                .bind(setting.mod_action_confirmation_message)
                .bind(setting.word_filter)
                .bind(setting.word_filter_blocklist)
                .bind(setting.word_filter_level)
                .bind(setting.word_filter_action)
                .bind(setting.word_filter_action_duration)
                .bind(setting.word_filter_action_duration_type)
                .bind(setting.invite_link_remover_action)
                .bind(setting.invite_link_remover_action_duration)
                .bind(setting.invite_link_remover_action_duration_type)
                .bind(setting.privacy_settings)
                .bind(setting.privacy_mod_log)
                .bind(setting.softban_threshold)
                .bind(setting.softban_action)
                .bind(setting.softban_action_duration)
                .bind(setting.softban_action_duration_type)
                .bind(setting.kick_threshold)
                .bind(setting.kick_action)
                .bind(setting.kick_action_duration)
                .bind(setting.kick_action_duration_type)
                .bind(setting.mute_threshold)
                .bind(setting.mute_action)
                .bind(setting.mute_action_duration)
                .bind(setting.mute_action_duration_type)
                .bind(setting.warn_threshold)
                .bind(setting.warn_action)
                .bind(setting.warn_action_duration)
                .bind(setting.warn_action_duration_type)
                .bind(setting.mods_can_edit_tags)
                .fetch_one(&*self.0)
                .await?,
        )
    }

    pub async fn update_setting(&self, setting: Setting) -> Result<(), Error> {
        sqlx::query(include_str!("sql/settings/update_entity.sql"))
            .bind(setting.guild_id)
            .bind(setting.mod_log)
            .bind(setting.mod_log_channel_id)
            .bind(setting.holding_room)
            .bind(setting.holding_room_role_id)
            .bind(setting.holding_room_minutes)
            .bind(setting.invite_link_remover)
            .bind(setting.welcome_message)
            .bind(setting.message)
            .bind(setting.welcome_message_channel_id)
            .bind(setting.prefix)
            .bind(setting.silent_commands)
            .bind(setting.no_space_prefix)
            .bind(setting.statistics)
            .bind(setting.join_captcha)
            .bind(setting.silent_commands_level)
            .bind(setting.mod_action_confirmation_message)
            .bind(setting.word_filter)
            .bind(setting.word_filter_blocklist)
            .bind(setting.word_filter_level)
            .bind(setting.word_filter_action)
            .bind(setting.word_filter_action_duration)
            .bind(setting.word_filter_action_duration_type)
            .bind(setting.invite_link_remover_action)
            .bind(setting.invite_link_remover_action_duration)
            .bind(setting.invite_link_remover_action_duration_type)
            .bind(setting.privacy_settings)
            .bind(setting.privacy_mod_log)
            .bind(setting.softban_threshold)
            .bind(setting.softban_action)
            .bind(setting.softban_action_duration)
            .bind(setting.softban_action_duration_type)
            .bind(setting.kick_threshold)
            .bind(setting.kick_action)
            .bind(setting.kick_action_duration)
            .bind(setting.kick_action_duration_type)
            .bind(setting.mute_threshold)
            .bind(setting.mute_action)
            .bind(setting.mute_action_duration)
            .bind(setting.mute_action_duration_type)
            .bind(setting.warn_threshold)
            .bind(setting.warn_action)
            .bind(setting.warn_action_duration)
            .bind(setting.warn_action_duration_type)
            .bind(setting.mods_can_edit_tags)
            .execute(&*self.0)
            .await?;

        Ok(())
    }

    pub async fn delete_setting(&self, guild_id: i64) -> Result<(), Error> {
        sqlx::query(include_str!("sql/settings/delete_setting.sql"))
            .bind(guild_id)
            .execute(&*self.0)
            .await?;

        Ok(())
    }
}
<commit_msg>Fix server prefix being intialized empty<commit_after>use std::sync::Arc;

use serenity::model::id::GuildId;
use sqlx::{Error, PgPool};
use std::time::Duration;
use tracing::warn;

const DEFAULT_WELCOME_MESSAGE: &str = "Welcome to $guild $user!";
const DEFAULT_PREFIX: &str = "-mod";

pub const SILENT_COMMANDS_MOD_ONLY: i32 = 0;
pub const SILENT_COMMANDS_ALL: i32 = 1;
pub const WORD_FILTER_LEVEL_LOW: i32 = 0;
pub const WORD_FILTER_LEVEL_HIGH: i32 = 1;
pub const ACTION_NOTHING: i32 = 0;
pub const ACTION_WARN: i32 = 1;
pub const ACTION_MUTE: i32 = 2;
pub const ACTION_KICK: i32 = 3;
pub const ACTION_BAN: i32 = 4;
pub const ACTION_SOFTBAN: i32 = 5;
pub const ACTION_HARDBAN: i32 = 6;
pub const DURATION_TYPE_SECONDS: i32 = 0;
pub const DURATION_TYPE_MINUTES: i32 = 1;
pub const DURATION_TYPE_HOURS: i32 = 2;
pub const DURATION_TYPE_DAYS: i32 = 3;
pub const PRIVACY_EVERYONE: i32 = 0;
pub const PRIVACY_STAFF_ONLY: i32 = 1;
pub const PRIVACY_ADMIN_ONLY: i32 = 2;

pub fn get_action_duration_for_auto_mod_action(
    kind: i32,
    duration_type: i32,
    duration: i32,
) -> Option<Duration> {
    if kind == ACTION_BAN || kind == ACTION_MUTE {
        if duration == 0 {
            None
        } else {
            Some(Duration::from_secs(if duration == DURATION_TYPE_SECONDS {
                duration
            } else if duration == DURATION_TYPE_MINUTES {
                duration * 60
            } else if duration == DURATION_TYPE_HOURS {
                duration * 60 * 60
            } else if duration == DURATION_TYPE_DAYS {
                duration * 60 * 60 * 24
            } else {
                warn!(
                    kind = kind,
                    duration_type = duration_type,
                    "invalid state for mod action duration type!"
                );
                return None;
            } as u64))
        }
    } else {
        None
    }
}

#[derive(sqlx::FromRow)]
pub struct Setting {
    pub guild_id: i64,
    pub mod_log: bool,
    pub mod_log_channel_id: i64,
    pub holding_room: bool,
    pub holding_room_role_id: Option<i64>,
    pub holding_room_minutes: i32,
    pub invite_link_remover: bool,
    pub welcome_message: bool,
    pub message: String,
    pub welcome_message_channel_id: i64,
    pub prefix: String,        // deprecated
    pub silent_commands: bool, // deprecated
    pub no_space_prefix: bool, // deprecated
    pub statistics: bool,      // deprecated
    pub join_captcha: bool,
    pub silent_commands_level: i32,            // deprecated
    pub mod_action_confirmation_message: bool, // deprecated
    pub word_filter: bool,
    pub word_filter_blocklist: Option<String>,
    pub word_filter_level: i32,
    pub word_filter_action: i32,
    pub word_filter_action_duration: i32,
    pub word_filter_action_duration_type: i32,
    pub invite_link_remover_action: i32,
    pub invite_link_remover_action_duration: i32,
    pub invite_link_remover_action_duration_type: i32,
    pub privacy_settings: i32,
    pub privacy_mod_log: i32,
    pub softban_threshold: i32,
    pub softban_action: i32,
    pub softban_action_duration: i32,
    pub softban_action_duration_type: i32,
    pub kick_threshold: i32,
    pub kick_action: i32,
    pub kick_action_duration: i32,
    pub kick_action_duration_type: i32,
    pub mute_threshold: i32,
    pub mute_action: i32,
    pub mute_action_duration: i32,
    pub mute_action_duration_type: i32,
    pub warn_threshold: i32,
    pub warn_action: i32,
    pub warn_action_duration: i32,
    pub warn_action_duration_type: i32,
    pub mods_can_edit_tags: bool,
}

impl Setting {
    pub fn default(guild_id: GuildId) -> Self {
        Setting {
            guild_id: guild_id.0 as i64,
            mod_log: false,
            mod_log_channel_id: 0,
            holding_room: false,
            holding_room_role_id: Option::None,
            holding_room_minutes: 3,
            invite_link_remover: false,
            welcome_message: false,
            message: DEFAULT_WELCOME_MESSAGE.into(),
            welcome_message_channel_id: 0,
            prefix: DEFAULT_PREFIX.into(),
            silent_commands: false,
            no_space_prefix: false,
            statistics: false,
            join_captcha: false,
            silent_commands_level: SILENT_COMMANDS_MOD_ONLY,
            mod_action_confirmation_message: true,
            word_filter: false,
            word_filter_blocklist: Option::None,
            word_filter_level: WORD_FILTER_LEVEL_LOW,
            word_filter_action: ACTION_WARN,
            word_filter_action_duration: 0,
            word_filter_action_duration_type: DURATION_TYPE_MINUTES,
            invite_link_remover_action: ACTION_WARN,
            invite_link_remover_action_duration: 0,
            invite_link_remover_action_duration_type: DURATION_TYPE_MINUTES,
            privacy_settings: PRIVACY_EVERYONE,
            privacy_mod_log: PRIVACY_EVERYONE,
            softban_threshold: 0,
            softban_action: ACTION_NOTHING,
            softban_action_duration: 0,
            softban_action_duration_type: DURATION_TYPE_MINUTES,
            kick_threshold: 0,
            kick_action: ACTION_NOTHING,
            kick_action_duration: 0,
            kick_action_duration_type: DURATION_TYPE_MINUTES,
            mute_threshold: 0,
            mute_action: ACTION_NOTHING,
            mute_action_duration: 0,
            mute_action_duration_type: DURATION_TYPE_MINUTES,
            warn_threshold: 0,
            warn_action: ACTION_NOTHING,
            warn_action_duration: 0,
            warn_action_duration_type: DURATION_TYPE_MINUTES,
            mods_can_edit_tags: false,
        }
    }
}

pub struct SettingsRepository(pub Arc<PgPool>);

impl SettingsRepository {
    pub async fn initialize(&self) -> Result<(), Error> {
        sqlx::query(include_str!("sql/settings/create_table.sql"))
            .execute(&*self.0)
            .await?;
        Ok(())
    }

    pub async fn fetch_setting(&self, guild_id: i64) -> Result<Option<Setting>, Error> {
        Ok(
            sqlx::query_as::<_, Setting>(include_str!("sql/settings/select_guild_setting.sql"))
                .bind(guild_id)
                .fetch_optional(&*self.0)
                .await?,
        )
    }

    pub async fn insert_setting(&self, setting: Setting) -> Result<Setting, Error> {
        Ok(
            sqlx::query_as::<_, Setting>(include_str!("sql/settings/insert_entity.sql"))
                .bind(setting.guild_id)
                .bind(setting.mod_log)
                .bind(setting.mod_log_channel_id)
                .bind(setting.holding_room)
                .bind(setting.holding_room_role_id)
                .bind(setting.holding_room_minutes)
                .bind(setting.invite_link_remover)
                .bind(setting.welcome_message)
                .bind(setting.message)
                .bind(setting.welcome_message_channel_id)
                .bind(setting.prefix)
                .bind(setting.silent_commands)
                .bind(setting.no_space_prefix)
                .bind(setting.statistics)
                .bind(setting.join_captcha)
                .bind(setting.silent_commands_level)
                .bind(setting.mod_action_confirmation_message)
                .bind(setting.word_filter)
                .bind(setting.word_filter_blocklist)
                .bind(setting.word_filter_level)
                .bind(setting.word_filter_action)
                .bind(setting.word_filter_action_duration)
                .bind(setting.word_filter_action_duration_type)
                .bind(setting.invite_link_remover_action)
                .bind(setting.invite_link_remover_action_duration)
                .bind(setting.invite_link_remover_action_duration_type)
                .bind(setting.privacy_settings)
                .bind(setting.privacy_mod_log)
                .bind(setting.softban_threshold)
                .bind(setting.softban_action)
                .bind(setting.softban_action_duration)
                .bind(setting.softban_action_duration_type)
                .bind(setting.kick_threshold)
                .bind(setting.kick_action)
                .bind(setting.kick_action_duration)
                .bind(setting.kick_action_duration_type)
                .bind(setting.mute_threshold)
                .bind(setting.mute_action)
                .bind(setting.mute_action_duration)
                .bind(setting.mute_action_duration_type)
                .bind(setting.warn_threshold)
                .bind(setting.warn_action)
                .bind(setting.warn_action_duration)
                .bind(setting.warn_action_duration_type)
                .bind(setting.mods_can_edit_tags)
                .fetch_one(&*self.0)
                .await?,
        )
    }

    pub async fn update_setting(&self, setting: Setting) -> Result<(), Error> {
        sqlx::query(include_str!("sql/settings/update_entity.sql"))
            .bind(setting.guild_id)
            .bind(setting.mod_log)
            .bind(setting.mod_log_channel_id)
            .bind(setting.holding_room)
            .bind(setting.holding_room_role_id)
            .bind(setting.holding_room_minutes)
            .bind(setting.invite_link_remover)
            .bind(setting.welcome_message)
            .bind(setting.message)
            .bind(setting.welcome_message_channel_id)
            .bind(setting.prefix)
            .bind(setting.silent_commands)
            .bind(setting.no_space_prefix)
            .bind(setting.statistics)
            .bind(setting.join_captcha)
            .bind(setting.silent_commands_level)
            .bind(setting.mod_action_confirmation_message)
            .bind(setting.word_filter)
            .bind(setting.word_filter_blocklist)
            .bind(setting.word_filter_level)
            .bind(setting.word_filter_action)
            .bind(setting.word_filter_action_duration)
            .bind(setting.word_filter_action_duration_type)
            .bind(setting.invite_link_remover_action)
            .bind(setting.invite_link_remover_action_duration)
            .bind(setting.invite_link_remover_action_duration_type)
            .bind(setting.privacy_settings)
            .bind(setting.privacy_mod_log)
            .bind(setting.softban_threshold)
            .bind(setting.softban_action)
            .bind(setting.softban_action_duration)
            .bind(setting.softban_action_duration_type)
            .bind(setting.kick_threshold)
            .bind(setting.kick_action)
            .bind(setting.kick_action_duration)
            .bind(setting.kick_action_duration_type)
            .bind(setting.mute_threshold)
            .bind(setting.mute_action)
            .bind(setting.mute_action_duration)
            .bind(setting.mute_action_duration_type)
            .bind(setting.warn_threshold)
            .bind(setting.warn_action)
            .bind(setting.warn_action_duration)
            .bind(setting.warn_action_duration_type)
            .bind(setting.mods_can_edit_tags)
            .execute(&*self.0)
            .await?;

        Ok(())
    }

    pub async fn delete_setting(&self, guild_id: i64) -> Result<(), Error> {
        sqlx::query(include_str!("sql/settings/delete_setting.sql"))
            .bind(guild_id)
            .execute(&*self.0)
            .await?;

        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Implements a bitboard for a single piece.

use std::collections::bitv_set::{self, BitvSet};
use std::iter::Map;

use super::super::square::Square;

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct BitBoard(BitvSet);
impl BitBoard {
    pub fn new() -> BitBoard { BitBoard(BitvSet::with_capacity(64)) }
    pub fn new_full() -> BitBoard {
        let mut ans = BitvSet::with_capacity(64);
        for i in 0..64_us {
            ans.insert(i);
        }
        BitBoard(ans)
    }

    pub fn at(&self, s: Square) -> bool { self.0.contains(&(s.to_id() as usize)) }
    pub fn set_at(&mut self, s: Square) { self.0.insert(s.to_id() as usize); }
    pub fn remove_at(&mut self, s: Square) { self.0.remove(&(s.to_id() as usize)); }

    pub fn iter(&self) -> Map<bitv_set::Iter, fn(usize)->Square> {
        fn map_fn(x: usize) -> Square { Square::from_id(x as i32) };
        self.0.iter().map( map_fn as fn(usize)->Square )
    }
}
<commit_msg>Implement custom bitboard with u64<commit_after>//! Implements a bitboard for a single piece.

use std::num::Int;

use super::super::square::Square;

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct BitBoard(u64);
impl BitBoard {
    pub fn new() -> BitBoard { BitBoard(0_u64) }
    pub fn new_full() -> BitBoard { BitBoard(!0_u64) }

    pub fn at(&self, s: Square) -> bool {
        self.0 & (1_u64 << s.to_id()) != 0
    }
    pub fn set_at(&mut self, s: Square) {
        debug_assert!(!self.at(s));
        self.0 |= 1_u64 << s.to_id();
    }
    pub fn remove_at(&mut self, s: Square) {
        debug_assert!(self.at(s));
        self.0 ^= 1_u64 << s.to_id();
    }

    pub fn iter(&self) -> Iter {
        Iter(self.0)
    }
}

#[derive(Debug)]
pub struct Iter(u64);
impl Iterator for Iter {
    type Item = Square;
    fn next(&mut self) -> Option<Square> {
        if self.0 == 0 {
            None
        } else {
            let res = self.0.trailing_zeros();
            self.0 &= !(1 << res);
            Some(Square::from_id(res as i32))
        }
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        let res = self.0.count_ones();
        (res, Some(res))
    }
}
<|endoftext|>


<commit_before>//! A Collection of Header implementations for common HTTP Headers.
//!
//! ## Mime
//!
//! Several header fields use MIME values for their contents. Keeping with the
//! strongly-typed theme, the [mime](http://seanmonstar.github.io/mime.rs) crate
//! is used, such as `ContentType(pub Mime)`.

pub use self::accept::Accept;
pub use self::access_control_allow_headers::AccessControlAllowHeaders;
pub use self::access_control_allow_methods::AccessControlAllowMethods;
pub use self::access_control_allow_origin::AccessControlAllowOrigin;
pub use self::access_control_max_age::AccessControlMaxAge;
pub use self::access_control_request_headers::AccessControlRequestHeaders;
pub use self::access_control_request_method::AccessControlRequestMethod;
pub use self::accept_charset::AcceptCharset;
pub use self::accept_encoding::AcceptEncoding;
pub use self::accept_language::AcceptLanguage;
pub use self::allow::Allow;
pub use self::authorization::{Authorization, Scheme, Basic};
pub use self::cache_control::{CacheControl, CacheDirective};
pub use self::connection::{Connection, ConnectionOption};
pub use self::content_length::ContentLength;
pub use self::content_encoding::ContentEncoding;
pub use self::content_language::ContentLanguage;
pub use self::content_type::ContentType;
pub use self::cookie::Cookie;
pub use self::date::Date;
pub use self::etag::ETag;
pub use self::expect::Expect;
pub use self::expires::Expires;
pub use self::host::Host;
pub use self::if_match::IfMatch;
pub use self::if_modified_since::IfModifiedSince;
pub use self::if_none_match::IfNoneMatch;
pub use self::if_unmodified_since::IfUnmodifiedSince;
pub use self::last_modified::LastModified;
pub use self::location::Location;
pub use self::pragma::Pragma;
pub use self::referer::Referer;
pub use self::server::Server;
pub use self::set_cookie::SetCookie;
pub use self::transfer_encoding::TransferEncoding;
pub use self::upgrade::{Upgrade, Protocol};
pub use self::user_agent::UserAgent;
pub use self::vary::Vary;

#[macro_export]
macro_rules! bench_header(
    ($name:ident, $ty:ty, $value:expr) => {
        #[cfg(test)]
        #[cfg(feature = "nightly")]
        mod $name {
            use test::Bencher;
            use super::*;

            use header::{Header, HeaderFormatter};

            #[bench]
            fn bench_parse(b: &mut Bencher) {
                let val = $value;
                b.iter(|| {
                    let _: $ty = Header::parse_header(&val[..]).unwrap();
                });
            }

            #[bench]
            fn bench_format(b: &mut Bencher) {
                let val: $ty = Header::parse_header(&$value[..]).unwrap();
                let fmt = HeaderFormatter(&val);
                b.iter(|| {
                    format!("{}", fmt);
                });
            }
        }
    }
);

#[macro_export]
macro_rules! deref(
    ($from:ty => $to:ty) => {
        impl ::std::ops::Deref for $from {
            type Target = $to;

            fn deref<'a>(&'a self) -> &'a $to {
                &self.0
            }
        }

        impl ::std::ops::DerefMut for $from {
            fn deref_mut<'a>(&'a mut self) -> &'a mut $to {
                &mut self.0
            }
        }
    }
);

macro_rules! test_header {
    ($id:ident, $raw:expr) => {
        #[test]
        fn $id() {
            use std::ascii::AsciiExt;
            let raw = $raw;
            let a: Vec<Vec<u8>> = raw.iter().map(|x| x.to_vec()).collect();
            let value = HeaderField::parse_header(&a[..]);
            let result = format!("{}", value.unwrap());
            let expected = String::from_utf8(raw[0].to_vec()).unwrap();
            let result_cmp: Vec<String> = result.to_ascii_lowercase().split(' ').map(|x| x.to_string()).collect();
            let expected_cmp: Vec<String> = expected.to_ascii_lowercase().split(' ').map(|x| x.to_string()).collect();
            assert_eq!(result_cmp.concat(), expected_cmp.concat());
        }
    };
    ($id:ident, $raw:expr, $typed:expr) => {
        #[test]
        fn $id() {
            let a: Vec<Vec<u8>> = $raw.iter().map(|x| x.to_vec()).collect();
            let val = HeaderField::parse_header(&a[..]);
            // Test parsing
            assert_eq!(val, $typed);
            // Test formatting
            if $typed != None {
                let res: &str = str::from_utf8($raw[0]).unwrap();
                assert_eq!(format!("{}", $typed.unwrap()), res);
            }
        }
    }
}

#[macro_export]
macro_rules! header {
    // $a:meta: Attributes associated with the header item (usually docs)
    // $id:ident: Identifier of the header
    // $n:expr: Lowercase name of the header
    // $nn:expr: Nice name of the header

    // List header, zero or more items
    ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)* $tm:ident{$($tf:item)*}) => {
        $(#[$a])*
        #[derive(Clone, Debug, PartialEq)]
        pub struct $id(pub Vec<$item>);
        deref!($id => Vec<$item>);
        impl $crate::header::Header for $id {
            fn header_name() -> &'static str {
                $n
            }
            fn parse_header(raw: &[Vec<u8>]) -> Option<Self> {
                $crate::header::parsing::from_comma_delimited(raw).map($id)
            }
        }
        impl $crate::header::HeaderFormat for $id {
            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                $crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
            }
        }
        impl ::std::fmt::Display for $id {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                use $crate::header::HeaderFormat;
                self.fmt_header(f)
            }
        }
        #[allow(unused_imports)]
        mod $tm{
            use std::str;
            use $crate::header::*;
            use $crate::mime::*;
            use $crate::method::Method;
            use super::$id as HeaderField;
            $($tf)*
        }

    };
    // List header, one or more items
    ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+ $tm:ident{$($tf:item)*}) => {
        $(#[$a])*
        #[derive(Clone, Debug, PartialEq)]
        pub struct $id(pub Vec<$item>);
        deref!($id => Vec<$item>);
        impl $crate::header::Header for $id {
            fn header_name() -> &'static str {
                $n
            }
            fn parse_header(raw: &[Vec<u8>]) -> Option<Self> {
                $crate::header::parsing::from_comma_delimited(raw).map($id)
            }
        }
        impl $crate::header::HeaderFormat for $id {
            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                $crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
            }
        }
        impl ::std::fmt::Display for $id {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                use $crate::header::HeaderFormat;
                self.fmt_header(f)
            }
        }
        #[allow(unused_imports)]
        mod $tm{
            use std::str;
            use $crate::header::*;
            use $crate::mime::*;
            use $crate::method::Method;
            use super::$id as HeaderField;
            $($tf)*
        }
    };
    // Single value header
    ($(#[$a:meta])*($id:ident, $n:expr) => [$value:ty] $tm:ident{$($tf:item)*}) => {
        $(#[$a])*
        #[derive(Clone, Debug, PartialEq)]
        pub struct $id(pub $value);
        deref!($id => $value);
        impl $crate::header::Header for $id {
            fn header_name() -> &'static str {
                $n
            }
            fn parse_header(raw: &[Vec<u8>]) -> Option<Self> {
                $crate::header::parsing::from_one_raw_str(raw).map($id)
            }
        }
        impl $crate::header::HeaderFormat for $id {
            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                ::std::fmt::Display::fmt(&**self, f)
            }
        }
        impl ::std::fmt::Display for $id {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                ::std::fmt::Display::fmt(&**self, f)
            }
        }
        #[allow(unused_imports)]
        mod $tm{
            use std::str;
            use $crate::header::*;
            use $crate::mime::*;
            use $crate::method::Method;
            use super::$id as HeaderField;
            $($tf)*
        }
    };
    // List header, one or more items with "*" option
    ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+} $tm:ident{$($tf:item)*}) => {
        $(#[$a])*
        #[derive(Clone, Debug, PartialEq)]
        pub enum $id {
            /// Any value is a match
            Any,
            /// Only the listed items are a match
            Items(Vec<$item>),
        }
        impl $crate::header::Header for $id {
            fn header_name() -> &'static str {
                $n
            }
            fn parse_header(raw: &[Vec<u8>]) -> Option<Self> {
                // FIXME: Return None if no item is in $id::Only
                if raw.len() == 1 {
                    if raw[0] == b"*" {
                        return Some($id::Any)
                    } else if raw[0] == b"" {
                        return None
                    }
                }
                $crate::header::parsing::from_comma_delimited(raw).map(|vec| $id::Items(vec))
            }
        }
        impl $crate::header::HeaderFormat for $id {
            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                match *self {
                    $id::Any => write!(f, "*"),
                    $id::Items(ref fields) => $crate::header::parsing::fmt_comma_delimited(f, &fields[..])
                }
            }
        }
        impl ::std::fmt::Display for $id {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                use $crate::header::HeaderFormat;
                self.fmt_header(f)
            }
        }
        #[allow(unused_imports)]
        mod $tm{
            use std::str;
            use $crate::header::*;
            use $crate::mime::*;
            use $crate::method::Method;
            use super::$id as HeaderField;
            $($tf)*
        }
    };
}

mod accept;
mod access_control_allow_headers;
mod access_control_allow_methods;
mod access_control_allow_origin;
mod access_control_max_age;
mod access_control_request_headers;
mod access_control_request_method;
mod accept_charset;
mod accept_encoding;
mod accept_language;
mod allow;
mod authorization;
mod cache_control;
mod cookie;
mod connection;
mod content_encoding;
mod content_language;
mod content_length;
mod content_type;
mod date;
mod etag;
mod expect;
mod expires;
mod host;
mod if_match;
mod last_modified;
mod if_modified_since;
mod if_none_match;
mod if_unmodified_since;
mod location;
mod pragma;
mod referer;
mod server;
mod set_cookie;
mod transfer_encoding;
mod upgrade;
mod user_agent;
mod vary;
<commit_msg>fix(header): exporting test_header! macro<commit_after>//! A Collection of Header implementations for common HTTP Headers.
//!
//! ## Mime
//!
//! Several header fields use MIME values for their contents. Keeping with the
//! strongly-typed theme, the [mime](http://seanmonstar.github.io/mime.rs) crate
//! is used, such as `ContentType(pub Mime)`.

pub use self::accept::Accept;
pub use self::access_control_allow_headers::AccessControlAllowHeaders;
pub use self::access_control_allow_methods::AccessControlAllowMethods;
pub use self::access_control_allow_origin::AccessControlAllowOrigin;
pub use self::access_control_max_age::AccessControlMaxAge;
pub use self::access_control_request_headers::AccessControlRequestHeaders;
pub use self::access_control_request_method::AccessControlRequestMethod;
pub use self::accept_charset::AcceptCharset;
pub use self::accept_encoding::AcceptEncoding;
pub use self::accept_language::AcceptLanguage;
pub use self::allow::Allow;
pub use self::authorization::{Authorization, Scheme, Basic};
pub use self::cache_control::{CacheControl, CacheDirective};
pub use self::connection::{Connection, ConnectionOption};
pub use self::content_length::ContentLength;
pub use self::content_encoding::ContentEncoding;
pub use self::content_language::ContentLanguage;
pub use self::content_type::ContentType;
pub use self::cookie::Cookie;
pub use self::date::Date;
pub use self::etag::ETag;
pub use self::expect::Expect;
pub use self::expires::Expires;
pub use self::host::Host;
pub use self::if_match::IfMatch;
pub use self::if_modified_since::IfModifiedSince;
pub use self::if_none_match::IfNoneMatch;
pub use self::if_unmodified_since::IfUnmodifiedSince;
pub use self::last_modified::LastModified;
pub use self::location::Location;
pub use self::pragma::Pragma;
pub use self::referer::Referer;
pub use self::server::Server;
pub use self::set_cookie::SetCookie;
pub use self::transfer_encoding::TransferEncoding;
pub use self::upgrade::{Upgrade, Protocol};
pub use self::user_agent::UserAgent;
pub use self::vary::Vary;

#[macro_export]
macro_rules! bench_header(
    ($name:ident, $ty:ty, $value:expr) => {
        #[cfg(test)]
        #[cfg(feature = "nightly")]
        mod $name {
            use test::Bencher;
            use super::*;

            use header::{Header, HeaderFormatter};

            #[bench]
            fn bench_parse(b: &mut Bencher) {
                let val = $value;
                b.iter(|| {
                    let _: $ty = Header::parse_header(&val[..]).unwrap();
                });
            }

            #[bench]
            fn bench_format(b: &mut Bencher) {
                let val: $ty = Header::parse_header(&$value[..]).unwrap();
                let fmt = HeaderFormatter(&val);
                b.iter(|| {
                    format!("{}", fmt);
                });
            }
        }
    }
);

#[macro_export]
macro_rules! deref(
    ($from:ty => $to:ty) => {
        impl ::std::ops::Deref for $from {
            type Target = $to;

            fn deref<'a>(&'a self) -> &'a $to {
                &self.0
            }
        }

        impl ::std::ops::DerefMut for $from {
            fn deref_mut<'a>(&'a mut self) -> &'a mut $to {
                &mut self.0
            }
        }
    }
);

#[macro_export]
macro_rules! test_header {
    ($id:ident, $raw:expr) => {
        #[test]
        fn $id() {
            use std::ascii::AsciiExt;
            let raw = $raw;
            let a: Vec<Vec<u8>> = raw.iter().map(|x| x.to_vec()).collect();
            let value = HeaderField::parse_header(&a[..]);
            let result = format!("{}", value.unwrap());
            let expected = String::from_utf8(raw[0].to_vec()).unwrap();
            let result_cmp: Vec<String> = result.to_ascii_lowercase().split(' ').map(|x| x.to_string()).collect();
            let expected_cmp: Vec<String> = expected.to_ascii_lowercase().split(' ').map(|x| x.to_string()).collect();
            assert_eq!(result_cmp.concat(), expected_cmp.concat());
        }
    };
    ($id:ident, $raw:expr, $typed:expr) => {
        #[test]
        fn $id() {
            let a: Vec<Vec<u8>> = $raw.iter().map(|x| x.to_vec()).collect();
            let val = HeaderField::parse_header(&a[..]);
            // Test parsing
            assert_eq!(val, $typed);
            // Test formatting
            if $typed != None {
                let res: &str = str::from_utf8($raw[0]).unwrap();
                assert_eq!(format!("{}", $typed.unwrap()), res);
            }
        }
    }
}

#[macro_export]
macro_rules! header {
    // $a:meta: Attributes associated with the header item (usually docs)
    // $id:ident: Identifier of the header
    // $n:expr: Lowercase name of the header
    // $nn:expr: Nice name of the header

    // List header, zero or more items
    ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)* $tm:ident{$($tf:item)*}) => {
        $(#[$a])*
        #[derive(Clone, Debug, PartialEq)]
        pub struct $id(pub Vec<$item>);
        deref!($id => Vec<$item>);
        impl $crate::header::Header for $id {
            fn header_name() -> &'static str {
                $n
            }
            fn parse_header(raw: &[Vec<u8>]) -> Option<Self> {
                $crate::header::parsing::from_comma_delimited(raw).map($id)
            }
        }
        impl $crate::header::HeaderFormat for $id {
            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                $crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
            }
        }
        impl ::std::fmt::Display for $id {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                use $crate::header::HeaderFormat;
                self.fmt_header(f)
            }
        }
        #[allow(unused_imports)]
        mod $tm{
            use std::str;
            use $crate::header::*;
            use $crate::mime::*;
            use $crate::method::Method;
            use super::$id as HeaderField;
            $($tf)*
        }

    };
    // List header, one or more items
    ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+ $tm:ident{$($tf:item)*}) => {
        $(#[$a])*
        #[derive(Clone, Debug, PartialEq)]
        pub struct $id(pub Vec<$item>);
        deref!($id => Vec<$item>);
        impl $crate::header::Header for $id {
            fn header_name() -> &'static str {
                $n
            }
            fn parse_header(raw: &[Vec<u8>]) -> Option<Self> {
                $crate::header::parsing::from_comma_delimited(raw).map($id)
            }
        }
        impl $crate::header::HeaderFormat for $id {
            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                $crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
            }
        }
        impl ::std::fmt::Display for $id {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                use $crate::header::HeaderFormat;
                self.fmt_header(f)
            }
        }
        #[allow(unused_imports)]
        mod $tm{
            use std::str;
            use $crate::header::*;
            use $crate::mime::*;
            use $crate::method::Method;
            use super::$id as HeaderField;
            $($tf)*
        }
    };
    // Single value header
    ($(#[$a:meta])*($id:ident, $n:expr) => [$value:ty] $tm:ident{$($tf:item)*}) => {
        $(#[$a])*
        #[derive(Clone, Debug, PartialEq)]
        pub struct $id(pub $value);
        deref!($id => $value);
        impl $crate::header::Header for $id {
            fn header_name() -> &'static str {
                $n
            }
            fn parse_header(raw: &[Vec<u8>]) -> Option<Self> {
                $crate::header::parsing::from_one_raw_str(raw).map($id)
            }
        }
        impl $crate::header::HeaderFormat for $id {
            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                ::std::fmt::Display::fmt(&**self, f)
            }
        }
        impl ::std::fmt::Display for $id {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                ::std::fmt::Display::fmt(&**self, f)
            }
        }
        #[allow(unused_imports)]
        mod $tm{
            use std::str;
            use $crate::header::*;
            use $crate::mime::*;
            use $crate::method::Method;
            use super::$id as HeaderField;
            $($tf)*
        }
    };
    // List header, one or more items with "*" option
    ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+} $tm:ident{$($tf:item)*}) => {
        $(#[$a])*
        #[derive(Clone, Debug, PartialEq)]
        pub enum $id {
            /// Any value is a match
            Any,
            /// Only the listed items are a match
            Items(Vec<$item>),
        }
        impl $crate::header::Header for $id {
            fn header_name() -> &'static str {
                $n
            }
            fn parse_header(raw: &[Vec<u8>]) -> Option<Self> {
                // FIXME: Return None if no item is in $id::Only
                if raw.len() == 1 {
                    if raw[0] == b"*" {
                        return Some($id::Any)
                    } else if raw[0] == b"" {
                        return None
                    }
                }
                $crate::header::parsing::from_comma_delimited(raw).map(|vec| $id::Items(vec))
            }
        }
        impl $crate::header::HeaderFormat for $id {
            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                match *self {
                    $id::Any => write!(f, "*"),
                    $id::Items(ref fields) => $crate::header::parsing::fmt_comma_delimited(f, &fields[..])
                }
            }
        }
        impl ::std::fmt::Display for $id {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                use $crate::header::HeaderFormat;
                self.fmt_header(f)
            }
        }
        #[allow(unused_imports)]
        mod $tm{
            use std::str;
            use $crate::header::*;
            use $crate::mime::*;
            use $crate::method::Method;
            use super::$id as HeaderField;
            $($tf)*
        }
    };
}

mod accept;
mod access_control_allow_headers;
mod access_control_allow_methods;
mod access_control_allow_origin;
mod access_control_max_age;
mod access_control_request_headers;
mod access_control_request_method;
mod accept_charset;
mod accept_encoding;
mod accept_language;
mod allow;
mod authorization;
mod cache_control;
mod cookie;
mod connection;
mod content_encoding;
mod content_language;
mod content_length;
mod content_type;
mod date;
mod etag;
mod expect;
mod expires;
mod host;
mod if_match;
mod last_modified;
mod if_modified_since;
mod if_none_match;
mod if_unmodified_since;
mod location;
mod pragma;
mod referer;
mod server;
mod set_cookie;
mod transfer_encoding;
mod upgrade;
mod user_agent;
mod vary;
<|endoftext|>