<commit_before>use std::error::Error;
use std::fmt;
use std::fmt::{ Display, Formatter };
use std::io;
use std::io::{ BufReader, ErrorKind, Read };
use std::result::Result;

/// Wrapper for a Reader, providing convenience methods to read the stream bit-by-bit.
///
/// # Examples
///
/// extern crate compression;
///
/// use compression::bitreader::BitReader;
/// use std::fs::File;
///
/// let f = try!(File::open("filename"));
/// let mut br = BitReader::new(f);
/// let byte: u8 = br.read_u8().unwrap();
#[derive(Debug)]
pub struct BitReader<R: Read> {
	inner: BufReader<R>,
	bit_pos: u8,
	current_byte: Option<u8>,
}

impl<R: Read> BitReader<R> {
	pub fn new(inner: R) -> BitReader<R> {
		BitReader{
			inner: BufReader::new(inner),
			bit_pos: 0,
			current_byte: None,
		}
	}

	fn read_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> {
		while !buf.is_empty() {
			match self.inner.read(buf) {
				Ok(0) => break,
				Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; }
				Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
				Err(e) => return Err(e),
			}
		}
		if !buf.is_empty() {
			Err(io::Error::new(ErrorKind::Other, "failed to fill whole buffer"))
		} else {
			Ok(())
		}
	}

	pub fn read_u8(&mut self) -> Result<u8, BitReaderError> {
		let mut buf = &mut [0u8];

		match (self.current_byte, self.read_exact(buf)) {
			(Some(byte), Ok(())) => {
				self.current_byte = Some(buf[0]);
				Ok((byte >> self.bit_pos) | (buf[0] << (8 - self.bit_pos)))
			},
			(None, Ok(())) => Ok(buf[0]),
			(_, Err(_)) => Err(BitReaderError::Unspecified),
		}
	}

	pub fn read_u16(&mut self) -> Result<u16, BitReaderError> {
		let mut buf = &mut [0u8; 2];

		match (self.current_byte, self.read_exact(buf)) {
			(Some(byte), Ok(())) => {
				self.current_byte = Some(buf[1]);
				Ok(((byte as u16) >> self.bit_pos) | ((buf[0] as u16) << (8 - self.bit_pos)) | ((buf[1] as u16) << (16 - self.bit_pos)))
			},
			(None, Ok(())) => Ok(((buf[1] as u16) << 8) | (buf[0] as u16)),
			(_, Err(_)) => Err(BitReaderError::Unspecified),
		}
	}

	pub fn read_u32(&mut self) -> Result<u32, BitReaderError> {
		match (self.read_u16(), self.read_u16()) {
			(Ok(my_u16_0), Ok(my_u16_1)) => Ok((my_u16_1 as u32) << 16 | (my_u16_0 as u32)),
			(_, _) => Err(BitReaderError::Unspecified),
		}
	}

	pub fn read_bit(&mut self) -> Result<bool, BitReaderError> {
		match (self.current_byte, self.bit_pos) {
			(Some(byte), bit_pos) => {
				self.bit_pos = (self.bit_pos + 1) % 8;
				if self.bit_pos == 0 {
					self.current_byte = None;
				}
				Ok(byte >> bit_pos & 1 == 1)
			},
			(None, _) => {
				let mut buf = &mut [0u8; 1];
				match self.read_exact(buf) {
					Ok(()) => {
						self.current_byte = Some(buf[0]);
						self.bit_pos = 1;
						Ok(buf[0] & 1 == 1)
					},
					Err(_) => Err(BitReaderError::Unspecified),
				}
			}
		}

	}
}

#[derive(Debug, Clone, PartialEq)]
pub enum BitReaderError {
	Unspecified
}

impl Display for BitReaderError {
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		fmt.write_str(self.description())
	}
}

impl Error for BitReaderError {
	fn description(&self) -> &str {
		match self {
			_ => "Generic error",
		}
	}
}

mod tests {
	#[test]
	fn should_read_one_u8() {
		use super::*;
		use std::io::{ Cursor };

		let expected = 0x1f;
		let mut br = BitReader::new(Cursor::new(vec![expected, 0x8b]));

		match br.read_u8() {
			Ok(byte) => assert_eq!(expected, byte),
			Err(_) => panic!("Should have read one byte"),
		}
	}

	#[test]
	fn should_read_two_u8() {
		use super::*;
		use std::io::{ Cursor };

		let (expected0, expected1) = (0x1f, 0x8b);
		let mut br = BitReader::new(Cursor::new(vec![expected0, expected1]));

		match (br.read_u8(), br.read_u8()) {
			(Ok(my_u8_0), Ok(my_u8_1)) => assert_eq!((expected0, expected1), (my_u8_0, my_u8_1)),
			_ => panic!("Should have read two bytes"),
		}
	}

	#[test]
	fn should_read_one_u16() {
		use super::*;
		use std::io::{ Cursor };

		let expected = 0x8b1f;
		let mut br = BitReader::new(Cursor::new(vec![(expected & 0x00FF) as u8, (expected >> 8) as u8]));

		match br.read_u16() {
			Ok(my_u16) => assert_eq!(expected, my_u16),
			_ => panic!("Should have read one u16"),
		}
	}

	#[test]
	fn should_read_one_set_bit() {
		use super::*;
		use std::io::{ Cursor };

		let mut br = BitReader::new(Cursor::new(vec![3]));

		match br.read_bit() {
			Ok(my_bit) => assert!(my_bit),
			_ => panic!("Should have read one set bit"),
		}
	}

	#[test]
	fn should_read_some_bits() {
		use super::*;
		use std::io::{ Cursor };

		let mut br = BitReader::new(Cursor::new(vec![134, 1]));

		match (br.read_bit(), br.read_bit(), br.read_bit(), br.read_bit(), br.read_bit(),
		       br.read_bit(), br.read_bit(), br.read_bit(), br.read_bit(), br.read_bit()) {
			(Ok(my_bit_0), Ok(my_bit_1), Ok(my_bit_2), Ok(my_bit_3), Ok(my_bit_4),
			 Ok(my_bit_5), Ok(my_bit_6), Ok(my_bit_7), Ok(my_bit_8), Ok(my_bit_9)) => {
				assert!(!my_bit_0);
				assert!(my_bit_1);
				assert!(my_bit_2);
				assert!(!my_bit_3);
				assert!(!my_bit_4);
				assert!(!my_bit_5);
				assert!(!my_bit_6);
				assert!(my_bit_7);
				assert!(my_bit_8);
				assert!(!my_bit_9);
			},
			_ => panic!("Should have read 10 bits"),
		}
	}

	#[test]
	fn should_read_u8_after_bit() {
		use super::*;
		use std::io::{ Cursor };

		let mut br = BitReader::new(Cursor::new(vec![0b10001101, 0b00010101]));

		match (br.read_bit(), br.read_u8()) {
			(Ok(my_bit), Ok(my_u8)) => {
				assert!(my_bit);
				assert_eq!(0b11000110, my_u8);
			},
			_ => panic!("Should have read one set bit and one u8"),
		}
	}

	#[test]
	fn should_read_u16_after_bit() {
		use super::*;
		use std::io::{ Cursor };

		let mut br = BitReader::new(Cursor::new(vec![0b10001101, 0b00010101, 0b00010101]));

		match (br.read_bit(), br.read_u16()) {
			(Ok(my_bit), Ok(my_u16)) => {
				assert!(my_bit);
				assert_eq!(0b1000101011000110, my_u16);
			},
			_ => panic!("Should have read one set bit and one u16"),
		}
	}

	#[test]
	fn should_read_u32() {
		use super::*;
		use std::io::{ Cursor };

		let mut br = BitReader::new(Cursor::new(vec![0x8e, 0x30, 0x04, 0x56]));

		match br.read_u32() {
			Ok(my_u32) => {
				assert_eq!(0x5604308e, my_u32);
			},
			_ => panic!("Should have read one u32"),
		}
	}
}

<commit_msg>MOD: read zero terminated string<commit_after>use std::error::Error;
use std::fmt;
use std::fmt::{ Display, Formatter };
use std::io;
use std::io::{ BufReader, ErrorKind, Read };
use std::result::Result;

/// Wrapper for a Reader, providing convenience methods to read the stream bit-by-bit.
///
/// # Examples
///
/// extern crate compression;
///
/// use compression::bitreader::BitReader;
/// use std::fs::File;
///
/// let f = try!(File::open("filename"));
/// let mut br = BitReader::new(f);
/// let byte: u8 = br.read_u8().unwrap();
#[derive(Debug)]
pub struct BitReader<R: Read> {
	inner: BufReader<R>,
	bit_pos: u8,
	current_byte: Option<u8>,
}

impl<R: Read> BitReader<R> {
	pub fn new(inner: R) -> BitReader<R> {
		BitReader{
			inner: BufReader::new(inner),
			bit_pos: 0,
			current_byte: None,
		}
	}

	fn read_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> {
		while !buf.is_empty() {
			match self.inner.read(buf) {
				Ok(0) => break,
				Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; }
				Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
				Err(e) => return Err(e),
			}
		}
		if !buf.is_empty() {
			Err(io::Error::new(ErrorKind::Other, "failed to fill whole buffer"))
		} else {
			Ok(())
		}
	}

	pub fn read_u8(&mut self) -> Result<u8, BitReaderError> {
		let mut buf = &mut [0u8];

		match (self.current_byte, self.read_exact(buf)) {
			(Some(byte), Ok(())) => {
				self.current_byte = Some(buf[0]);
				Ok((byte >> self.bit_pos) | (buf[0] << (8 - self.bit_pos)))
			},
			(None, Ok(())) => Ok(buf[0]),
			(_, Err(_)) => Err(BitReaderError::Unspecified),
		}
	}

	pub fn read_u16(&mut self) -> Result<u16, BitReaderError> {
		let mut buf = &mut [0u8; 2];

		match (self.current_byte, self.read_exact(buf)) {
			(Some(byte), Ok(())) => {
				self.current_byte = Some(buf[1]);
				Ok(((byte as u16) >> self.bit_pos) | ((buf[0] as u16) << (8 - self.bit_pos)) | ((buf[1] as u16) << (16 - self.bit_pos)))
			},
			(None, Ok(())) => Ok(((buf[1] as u16) << 8) | (buf[0] as u16)),
			(_, Err(_)) => Err(BitReaderError::Unspecified),
		}
	}

	pub fn read_u32(&mut self) -> Result<u32, BitReaderError> {
		match (self.read_u16(), self.read_u16()) {
			(Ok(my_u16_0), Ok(my_u16_1)) => Ok((my_u16_1 as u32) << 16 | (my_u16_0 as u32)),
			(_, _) => Err(BitReaderError::Unspecified),
		}
	}

	pub fn read_bit(&mut self) -> Result<bool, BitReaderError> {
		match (self.current_byte, self.bit_pos) {
			(Some(byte), bit_pos) => {
				self.bit_pos = (self.bit_pos + 1) % 8;
				if self.bit_pos == 0 {
					self.current_byte = None;
				}
				Ok(byte >> bit_pos & 1 == 1)
			},
			(None, _) => {
				let mut buf = &mut [0u8; 1];
				match self.read_exact(buf) {
					Ok(()) => {
						self.current_byte = Some(buf[0]);
						self.bit_pos = 1;
						Ok(buf[0] & 1 == 1)
					},
					Err(_) => Err(BitReaderError::Unspecified),
				}
			}
		}
	}

	pub fn read_zero_terminated_string(&mut self) -> Result<Vec<u8>, BitReaderError> {
		let mut my_string = Vec::with_capacity(16);

		loop {
			match self.read_u8() {
				Ok(0) => break,
				Ok(byte) => my_string.push(byte),
				Err(_) => return Err(BitReaderError::Unspecified),
			}
		}

		Ok(my_string)
	}
}

#[derive(Debug, Clone, PartialEq)]
pub enum BitReaderError {
	Unspecified
}

impl Display for BitReaderError {
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		fmt.write_str(self.description())
	}
}

impl Error for BitReaderError {
	fn description(&self) -> &str {
		match self {
			_ => "Generic error",
		}
	}
}

mod tests {
	#[test]
	fn should_read_one_u8() {
		use super::*;
		use std::io::{ Cursor };

		let expected = 0x1f;
		let mut br = BitReader::new(Cursor::new(vec![expected, 0x8b]));

		match br.read_u8() {
			Ok(byte) => assert_eq!(expected, byte),
			Err(_) => panic!("Should have read one byte"),
		}
	}

	#[test]
	fn should_read_two_u8() {
		use super::*;
		use std::io::{ Cursor };

		let (expected0, expected1) = (0x1f, 0x8b);
		let mut br = BitReader::new(Cursor::new(vec![expected0, expected1]));

		match (br.read_u8(), br.read_u8()) {
			(Ok(my_u8_0), Ok(my_u8_1)) => assert_eq!((expected0, expected1), (my_u8_0, my_u8_1)),
			_ => panic!("Should have read two bytes"),
		}
	}

	#[test]
	fn should_read_one_u16() {
		use super::*;
		use std::io::{ Cursor };

		let expected = 0x8b1f;
		let mut br = BitReader::new(Cursor::new(vec![(expected & 0x00FF) as u8, (expected >> 8) as u8]));

		match br.read_u16() {
			Ok(my_u16) => assert_eq!(expected, my_u16),
			_ => panic!("Should have read one u16"),
		}
	}

	#[test]
	fn should_read_one_set_bit() {
		use super::*;
		use std::io::{ Cursor };

		let mut br = BitReader::new(Cursor::new(vec![3]));

		match br.read_bit() {
			Ok(my_bit) => assert!(my_bit),
			_ => panic!("Should have read one set bit"),
		}
	}

	#[test]
	fn should_read_some_bits() {
		use super::*;
		use std::io::{ Cursor };

		let mut br = BitReader::new(Cursor::new(vec![134, 1]));

		match (br.read_bit(), br.read_bit(), br.read_bit(), br.read_bit(), br.read_bit(),
		       br.read_bit(), br.read_bit(), br.read_bit(), br.read_bit(), br.read_bit()) {
			(Ok(my_bit_0), Ok(my_bit_1), Ok(my_bit_2), Ok(my_bit_3), Ok(my_bit_4),
			 Ok(my_bit_5), Ok(my_bit_6), Ok(my_bit_7), Ok(my_bit_8), Ok(my_bit_9)) => {
				assert!(!my_bit_0);
				assert!(my_bit_1);
				assert!(my_bit_2);
				assert!(!my_bit_3);
				assert!(!my_bit_4);
				assert!(!my_bit_5);
				assert!(!my_bit_6);
				assert!(my_bit_7);
				assert!(my_bit_8);
				assert!(!my_bit_9);
			},
			_ => panic!("Should have read 10 bits"),
		}
	}

	#[test]
	fn should_read_u8_after_bit() {
		use super::*;
		use std::io::{ Cursor };

		let mut br = BitReader::new(Cursor::new(vec![0b10001101, 0b00010101]));

		match (br.read_bit(), br.read_u8()) {
			(Ok(my_bit), Ok(my_u8)) => {
				assert!(my_bit);
				assert_eq!(0b11000110, my_u8);
			},
			_ => panic!("Should have read one set bit and one u8"),
		}
	}

	#[test]
	fn should_read_u16_after_bit() {
		use super::*;
		use std::io::{ Cursor };

		let mut br = BitReader::new(Cursor::new(vec![0b10001101, 0b00010101, 0b00010101]));

		match (br.read_bit(), br.read_u16()) {
			(Ok(my_bit), Ok(my_u16)) => {
				assert!(my_bit);
				assert_eq!(0b1000101011000110, my_u16);
			},
			_ => panic!("Should have read one set bit and one u16"),
		}
	}

	#[test]
	fn should_read_u32() {
		use super::*;
		use std::io::{ Cursor };

		let mut br = BitReader::new(Cursor::new(vec![0x8e, 0x30, 0x04, 0x56]));

		match br.read_u32() {
			Ok(my_u32) => {
				assert_eq!(0x5604308e, my_u32);
			},
			_ => panic!("Should have read one u32"),
		}
	}

	#[test]
	fn should_read_zero_terminated_string() {
		use super::*;
		use std::io::{ Cursor };

		let mut br = BitReader::new(Cursor::new(vec![
			0x78, 0x78, 0x78, 0x78, 0x78,
			0x79, 0x79, 0x79, 0x79, 0x79,
			0x2e, 0x74, 0x78, 0x74, 0x00,
			0x78, 0x78, 0x78, 0x78, 0x78,
			0x79, 0x79, 0x79, 0x79, 0x79,
			0x2e, 0x74, 0x78, 0x74, 0x00,
		]));

		match br.read_zero_terminated_string() {
			Ok(my_vec) => assert_eq!("xxxxxyyyyy.txt", &(String::from_utf8(my_vec).unwrap())),
			_ => panic!("Should have read zero-terminated string"),
		}
	}
}

<|endoftext|>


<commit_before>use super::{
    external_libraries::{read_external_libraries, ExternalLibrary},
    gobjects, WorkMode,
};
use crate::{
    config::error::TomlHelper,
    git::repo_hash,
    library::{self, Library},
    nameutil::set_crate_name_overrides,
    version::Version,
};
use log::warn;
use std::{
    collections::HashMap,
    fs::File,
    io::Read,
    path::{Path, PathBuf},
    str::FromStr,
};

#[derive(Debug)]
pub struct Config {
    pub work_mode: WorkMode,
    pub girs_dir: PathBuf,
    pub girs_version: String, //Version in girs_dir, detected by git
    pub library_name: String,
    pub library_version: String,
    pub target_path: PathBuf,
    /// Path where files generated in normal and sys mode
    pub auto_path: PathBuf,
    pub doc_target_path: PathBuf,
    pub external_libraries: Vec<ExternalLibrary>,
    pub objects: gobjects::GObjects,
    pub min_cfg_version: Version,
    pub make_backup: bool,
    pub generate_safety_asserts: bool,
    pub deprecate_by_min_version: bool,
    pub show_statistics: bool,
    pub concurrency: library::Concurrency,
    pub single_version_file: Option<PathBuf>,
    pub generate_display_trait: bool,
    pub docs_rs_features: Vec<String>,
    pub disable_format: bool,
    pub split_build_rs: bool,
    pub extra_versions: Vec<Version>,
    pub lib_version_overrides: HashMap<Version, Version>,
    pub feature_dependencies: HashMap<Version, Vec<String>>,
}

impl Config {
    pub fn new<'a, S, B, W>(
        config_file: S,
        work_mode: W,
        girs_dir: S,
        library_name: S,
        library_version: S,
        target_path: S,
        doc_target_path: S,
        make_backup: B,
        show_statistics: B,
        disable_format: B,
    ) -> Result<Config, String>
    where
        S: Into<Option<&'a str>>,
        B: Into<Option<bool>>,
        W: Into<Option<WorkMode>>,
    {
        let config_file: PathBuf = match config_file.into() {
            Some("") | None => "Gir.toml",
            Some(a) => a,
        }
        .into();

        let config_dir = match config_file.parent() {
            Some(path) => path.into(),
            None => PathBuf::new(),
        };

        let toml = match read_toml(&config_file) {
            Ok(toml) => toml,
            Err(e) => {
                return Err(format!(
                    "Error while reading \"{}\": {}",
                    config_file.display(),
                    e
                ))
            }
        };

        let overrides = read_crate_name_overrides(&toml);
        if !overrides.is_empty() {
            set_crate_name_overrides(overrides);
        }

        let work_mode = match work_mode.into() {
            Some(w) => w,
            None => {
                let s = match toml.lookup_str("options.work_mode", "No options.work_mode") {
                    Ok(s) => s,
                    Err(e) => {
                        return Err(format!(
                            "Invalid toml file \"{}\": {}",
                            config_file.display(),
                            e
                        ))
                    }
                };
                WorkMode::from_str(s)?
            }
        };

        let girs_dir: PathBuf = match girs_dir.into() {
            Some("") | None => {
                let path = toml.lookup_str("options.girs_dir", "No options.girs_dir")?;
                config_dir.join(path)
            }
            Some(a) => a.into(),
        };
        let girs_version = repo_hash(&girs_dir).unwrap_or_else(|| "???".into());

        let (library_name, library_version) = match (library_name.into(), library_version.into()) {
            (Some(""), Some("")) | (None, None) => (
                toml.lookup_str("options.library", "No options.library")?
                    .to_owned(),
                toml.lookup_str("options.version", "No options.version")?
                    .to_owned(),
            ),
            (Some(""), Some(_)) | (Some(_), Some("")) | (None, Some(_)) | (Some(_), None) => {
                return Err("Library and version can not be specified separately".to_owned())
            }
            (Some(a), Some(b)) => (a.to_owned(), b.to_owned()),
        };

        let target_path: PathBuf = match target_path.into() {
            Some("") | None => {
                let path = toml.lookup_str("options.target_path", "No target path specified")?;
                config_dir.join(path)
            }
            Some(a) => a.into(),
        };

        let auto_path = match toml.lookup("options.auto_path") {
            Some(p) => target_path.join(p.as_result_str("options.auto_path")?),
            None if work_mode == WorkMode::Normal => target_path.join("src").join("auto"),
            None => target_path.join("src"),
        };

        let doc_target_path: PathBuf = match doc_target_path.into() {
            Some("") | None => match toml.lookup("options.doc_target_path") {
                Some(p) => config_dir.join(p.as_result_str("options.doc_target_path")?),
                None => target_path.join("vendor.md"),
            },
            Some(p) => config_dir.join(p),
        };

        let concurrency = match toml.lookup("options.concurrency") {
            Some(v) => v.as_result_str("options.concurrency")?.parse()?,
            None => Default::default(),
        };

        let generate_display_trait = match toml.lookup("options.generate_display_trait") {
            Some(v) => v.as_result_bool("options.generate_display_trait")?,
            None => true,
        };

        let mut docs_rs_features = Vec::new();
        for v in match toml.lookup("options.docs_rs_features") {
            Some(v) => v.as_result_vec("options.docs_rs_features")?.as_slice(),
            None => &[],
        } {
            docs_rs_features.push(match v.as_str() {
                Some(s) => s.to_owned(),
                None => {
                    return Err(format!(
                        "Invalid `docs_rs_features` value element, expected a string, found {}",
                        v.type_str()
                    ))
                }
            });
        }

        // options.concurrency is the default of all objects if nothing
        // else is configured
        let mut objects = toml
            .lookup("object")
            .map(|t| gobjects::parse_toml(t, concurrency, generate_display_trait))
            .unwrap_or_default();
        gobjects::parse_status_shorthands(&mut objects, &toml, concurrency, generate_display_trait);
        gobjects::parse_builders(&mut objects, &toml);

        let external_libraries = read_external_libraries(&toml)?;

        let min_cfg_version = match toml.lookup("options.min_cfg_version") {
            Some(v) => v.as_result_str("options.min_cfg_version")?.parse()?,
            None => Default::default(),
        };

        let generate_safety_asserts = match toml.lookup("options.generate_safety_asserts") {
            Some(v) => v.as_result_bool("options.generate_safety_asserts")?,
            None => false,
        };

        let deprecate_by_min_version = match toml.lookup("options.deprecate_by_min_version") {
            Some(v) => v.as_result_bool("options.deprecate_by_min_version")?,
            None => false,
        };

        let single_version_file = match toml.lookup("options.single_version_file") {
            Some(v) => match v.as_result_bool("options.single_version_file") {
                Ok(false) => None,
                Ok(true) => Some(make_single_version_file(None, &target_path)),
                Err(_) => match v.as_str() {
                    Some(p) => Some(make_single_version_file(Some(p), &target_path)),
                    None => return Err("single_version_file must be bool or string path".into()),
                },
            },
            None => None,
        };

        let disable_format: bool = if let Some(disable_format) = disable_format.into() {
            disable_format
        } else {
            match toml.lookup("options.disable_format") {
                Some(v) => v.as_result_bool("options.disable_format")?,
                None => false,
            }
        };

        let split_build_rs = match toml.lookup("options.split_build_rs") {
            Some(v) => v.as_result_bool("options.split_build_rs")?,
            None => false,
        };

        let extra_versions = read_extra_versions(&toml)?;
        let lib_version_overrides = read_lib_version_overrides(&toml)?;
        let feature_dependencies = read_feature_dependencies(&toml)?;

        Ok(Config {
            work_mode,
            girs_dir,
            girs_version,
            library_name,
            library_version,
            target_path,
            auto_path,
            doc_target_path,
            external_libraries,
            objects,
            min_cfg_version,
            make_backup: make_backup.into().unwrap_or(false),
            generate_safety_asserts,
            deprecate_by_min_version,
            show_statistics: show_statistics.into().unwrap_or(false),
            concurrency,
            single_version_file,
            generate_display_trait,
            docs_rs_features,
            disable_format,
            split_build_rs,
            extra_versions,
            lib_version_overrides,
            feature_dependencies,
        })
    }

    pub fn library_full_name(&self) -> String {
        format!("{}-{}", self.library_name, self.library_version)
    }

    pub fn filter_version(&self, version: Option<Version>) -> Option<Version> {
        version.and_then(|v| {
            if v > self.min_cfg_version {
                Some(v)
            } else {
                None
            }
        })
    }

    pub fn resolve_type_ids(&mut self, library: &Library) {
        gobjects::resolve_type_ids(&mut self.objects, library)
    }

    pub fn check_disable_format(&mut self) {
        if !self.disable_format && !crate::fmt::check_fmt() {
            warn!("Formatter not found, options.disable_format set to true");
            self.disable_format = true;
        }
    }
}

fn read_toml<P: AsRef<Path>>(filename: P) -> Result<toml::Value, String> {
    if !filename.as_ref().is_file() {
        return Err("Config don't exists or not file".to_owned());
    }
    let mut input = String::new();
    match File::open(&filename) {
        Ok(mut f) => {
            if let Err(e) = f.read_to_string(&mut input) {
                return Err(format!(
                    "read_to_string failed on \"{}\": {}",
                    filename.as_ref().display(),
                    e
                ));
            }

            match toml::from_str(&input) {
                Ok(toml) => Ok(toml),
                Err(e) => Err(format!(
                    "Invalid toml format in \"{}\": {}",
                    filename.as_ref().display(),
                    e
                )),
            }
        }
        Err(e) => Err(format!(
            "Cannot open file \"{}\": {}",
            filename.as_ref().display(),
            e
        )),
    }
}

fn make_single_version_file(configured: Option<&str>, target_path: &Path) -> PathBuf {
    let file_dir = match configured {
        None | Some("") => target_path.join("src").join("auto"),
        Some(path) => target_path.join(path),
    };

    if file_dir.extension().is_some() {
        file_dir
    } else {
        file_dir.join("versions.txt")
    }
}

fn read_crate_name_overrides(toml: &toml::Value) -> HashMap<String, String> {
    let mut overrides = HashMap::new();
    if let Some(a) = toml
        .lookup("crate_name_overrides")
        .and_then(toml::Value::as_table)
    {
        for (key, value) in a {
            if let Some(s) = value.as_str() {
                overrides.insert(key.clone(), s.to_string());
            }
        }
    };
    overrides
}

fn read_extra_versions(toml: &toml::Value) -> Result<Vec<Version>, String> {
    match toml.lookup("options.extra_versions") {
        Some(a) => a
            .as_result_vec("options.extra_versions")?
            .iter()
            .map(|v| {
                v.as_str().ok_or_else(|| {
                    "options.extra_versions expected to be array of string".to_string()
                })
            })
            .map(|s| s.and_then(str::parse))
            .collect(),
        None => Ok(Vec::new()),
    }
}

fn read_lib_version_overrides(toml: &toml::Value) -> Result<HashMap<Version, Version>, String> {
    let v = match toml.lookup("lib_version_overrides") {
        Some(a) => a.as_result_vec("lib_version_overrides")?,
        None => return Ok(Default::default()),
    };

    let mut map = HashMap::with_capacity(v.len());
    for o in v {
        let cfg = o
            .lookup_str("version", "No version in lib_version_overrides")?
            .parse()?;
        let lib = o
            .lookup_str("lib_version", "No lib_version in lib_version_overrides")?
            .parse()?;
        map.insert(cfg, lib);
    }

    Ok(map)
}

fn read_feature_dependencies(toml: &toml::Value) -> Result<HashMap<Version, Vec<String>>, String> {
    let v = match toml.lookup("feature_dependencies") {
        Some(a) => a.as_result_vec("feature_dependencies")?,
        None => return Ok(Default::default()),
    };

    let mut map = HashMap::with_capacity(v.len());
    for o in v {
        let cfg = o
            .lookup_str("version", "No version in feature_dependencies")?
            .parse()?;
        let dependencies: Result<Vec<String>, String> = o
            .lookup_vec("dependencies", "No dependencies in feature_dependencies")?
            .iter()
            .map(|v| {
                v.as_str()
                    .ok_or_else(|| {
                        "feature_dependencies.dependencies expected to be array of string"
                            .to_string()
                    })
                    .map(str::to_owned)
            })
            .collect();
        map.insert(cfg, dependencies?);
    }

    Ok(map)
}

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

    #[test]
    fn test_make_single_version_file() {
        let target_path = Path::new("/tmp/glib");
        assert_eq!(
            make_single_version_file(None, &target_path),
            PathBuf::from("/tmp/glib/src/auto/versions.txt")
        );
        assert_eq!(
            make_single_version_file(Some(""), &target_path),
            PathBuf::from("/tmp/glib/src/auto/versions.txt")
        );
        assert_eq!(
            make_single_version_file(Some("src"), &target_path),
            PathBuf::from("/tmp/glib/src/versions.txt")
        );
        assert_eq!(
            make_single_version_file(Some("src/vers.txt"), &target_path),
            PathBuf::from("/tmp/glib/src/vers.txt")
        );
        assert_eq!(
            make_single_version_file(Some("."), &target_path),
            PathBuf::from("/tmp/glib/versions.txt")
        );
        assert_eq!(
            make_single_version_file(Some("./_vers.dat"), &target_path),
            PathBuf::from("/tmp/glib/_vers.dat")
        );
    }
}
<commit_msg>Make disable_format true by default<commit_after>use super::{
    external_libraries::{read_external_libraries, ExternalLibrary},
    gobjects, WorkMode,
};
use crate::{
    config::error::TomlHelper,
    git::repo_hash,
    library::{self, Library},
    nameutil::set_crate_name_overrides,
    version::Version,
};
use log::warn;
use std::{
    collections::HashMap,
    fs::File,
    io::Read,
    path::{Path, PathBuf},
    str::FromStr,
};

#[derive(Debug)]
pub struct Config {
    pub work_mode: WorkMode,
    pub girs_dir: PathBuf,
    pub girs_version: String, //Version in girs_dir, detected by git
    pub library_name: String,
    pub library_version: String,
    pub target_path: PathBuf,
    /// Path where files generated in normal and sys mode
    pub auto_path: PathBuf,
    pub doc_target_path: PathBuf,
    pub external_libraries: Vec<ExternalLibrary>,
    pub objects: gobjects::GObjects,
    pub min_cfg_version: Version,
    pub make_backup: bool,
    pub generate_safety_asserts: bool,
    pub deprecate_by_min_version: bool,
    pub show_statistics: bool,
    pub concurrency: library::Concurrency,
    pub single_version_file: Option<PathBuf>,
    pub generate_display_trait: bool,
    pub docs_rs_features: Vec<String>,
    pub disable_format: bool,
    pub split_build_rs: bool,
    pub extra_versions: Vec<Version>,
    pub lib_version_overrides: HashMap<Version, Version>,
    pub feature_dependencies: HashMap<Version, Vec<String>>,
}

impl Config {
    pub fn new<'a, S, W>(
        config_file: S,
        work_mode: W,
        girs_dir: S,
        library_name: S,
        library_version: S,
        target_path: S,
        doc_target_path: S,
        make_backup: bool,
        show_statistics: bool,
        disable_format: bool,
    ) -> Result<Config, String>
    where
        S: Into<Option<&'a str>>,
        W: Into<Option<WorkMode>>,
    {
        let config_file: PathBuf = match config_file.into() {
            Some("") | None => "Gir.toml",
            Some(a) => a,
        }
        .into();

        let config_dir = match config_file.parent() {
            Some(path) => path.into(),
            None => PathBuf::new(),
        };

        let toml = match read_toml(&config_file) {
            Ok(toml) => toml,
            Err(e) => {
                return Err(format!(
                    "Error while reading \"{}\": {}",
                    config_file.display(),
                    e
                ))
            }
        };

        let overrides = read_crate_name_overrides(&toml);
        if !overrides.is_empty() {
            set_crate_name_overrides(overrides);
        }

        let work_mode = match work_mode.into() {
            Some(w) => w,
            None => {
                let s = match toml.lookup_str("options.work_mode", "No options.work_mode") {
                    Ok(s) => s,
                    Err(e) => {
                        return Err(format!(
                            "Invalid toml file \"{}\": {}",
                            config_file.display(),
                            e
                        ))
                    }
                };
                WorkMode::from_str(s)?
            }
        };

        let girs_dir: PathBuf = match girs_dir.into() {
            Some("") | None => {
                let path = toml.lookup_str("options.girs_dir", "No options.girs_dir")?;
                config_dir.join(path)
            }
            Some(a) => a.into(),
        };
        let girs_version = repo_hash(&girs_dir).unwrap_or_else(|| "???".into());

        let (library_name, library_version) = match (library_name.into(), library_version.into()) {
            (Some(""), Some("")) | (None, None) => (
                toml.lookup_str("options.library", "No options.library")?
                    .to_owned(),
                toml.lookup_str("options.version", "No options.version")?
                    .to_owned(),
            ),
            (Some(""), Some(_)) | (Some(_), Some("")) | (None, Some(_)) | (Some(_), None) => {
                return Err("Library and version can not be specified separately".to_owned())
            }
            (Some(a), Some(b)) => (a.to_owned(), b.to_owned()),
        };

        let target_path: PathBuf = match target_path.into() {
            Some("") | None => {
                let path = toml.lookup_str("options.target_path", "No target path specified")?;
                config_dir.join(path)
            }
            Some(a) => a.into(),
        };

        let auto_path = match toml.lookup("options.auto_path") {
            Some(p) => target_path.join(p.as_result_str("options.auto_path")?),
            None if work_mode == WorkMode::Normal => target_path.join("src").join("auto"),
            None => target_path.join("src"),
        };

        let doc_target_path: PathBuf = match doc_target_path.into() {
            Some("") | None => match toml.lookup("options.doc_target_path") {
                Some(p) => config_dir.join(p.as_result_str("options.doc_target_path")?),
                None => target_path.join("vendor.md"),
            },
            Some(p) => config_dir.join(p),
        };

        let concurrency = match toml.lookup("options.concurrency") {
            Some(v) => v.as_result_str("options.concurrency")?.parse()?,
            None => Default::default(),
        };

        let generate_display_trait = match toml.lookup("options.generate_display_trait") {
            Some(v) => v.as_result_bool("options.generate_display_trait")?,
            None => true,
        };

        let mut docs_rs_features = Vec::new();
        for v in match toml.lookup("options.docs_rs_features") {
            Some(v) => v.as_result_vec("options.docs_rs_features")?.as_slice(),
            None => &[],
        } {
            docs_rs_features.push(match v.as_str() {
                Some(s) => s.to_owned(),
                None => {
                    return Err(format!(
                        "Invalid `docs_rs_features` value element, expected a string, found {}",
                        v.type_str()
                    ))
                }
            });
        }

        // options.concurrency is the default of all objects if nothing
        // else is configured
        let mut objects = toml
            .lookup("object")
            .map(|t| gobjects::parse_toml(t, concurrency, generate_display_trait))
            .unwrap_or_default();
        gobjects::parse_status_shorthands(&mut objects, &toml, concurrency, generate_display_trait);
        gobjects::parse_builders(&mut objects, &toml);

        let external_libraries = read_external_libraries(&toml)?;

        let min_cfg_version = match toml.lookup("options.min_cfg_version") {
            Some(v) => v.as_result_str("options.min_cfg_version")?.parse()?,
            None => Default::default(),
        };

        let generate_safety_asserts = match toml.lookup("options.generate_safety_asserts") {
            Some(v) => v.as_result_bool("options.generate_safety_asserts")?,
            None => false,
        };

        let deprecate_by_min_version = match toml.lookup("options.deprecate_by_min_version") {
            Some(v) => v.as_result_bool("options.deprecate_by_min_version")?,
            None => false,
        };

        let single_version_file = match toml.lookup("options.single_version_file") {
            Some(v) => match v.as_result_bool("options.single_version_file") {
                Ok(false) => None,
                Ok(true) => Some(make_single_version_file(None, &target_path)),
                Err(_) => match v.as_str() {
                    Some(p) => Some(make_single_version_file(Some(p), &target_path)),
                    None => return Err("single_version_file must be bool or string path".into()),
                },
            },
            None => None,
        };

        let disable_format: bool = if disable_format {
            true
        } else {
            match toml.lookup("options.disable_format") {
                Some(v) => v.as_result_bool("options.disable_format")?,
                None => true,
            }
        };

        let split_build_rs = match toml.lookup("options.split_build_rs") {
            Some(v) => v.as_result_bool("options.split_build_rs")?,
            None => false,
        };

        let extra_versions = read_extra_versions(&toml)?;
        let lib_version_overrides = read_lib_version_overrides(&toml)?;
        let feature_dependencies = read_feature_dependencies(&toml)?;

        Ok(Config {
            work_mode,
            girs_dir,
            girs_version,
            library_name,
            library_version,
            target_path,
            auto_path,
            doc_target_path,
            external_libraries,
            objects,
            min_cfg_version,
            make_backup,
            generate_safety_asserts,
            deprecate_by_min_version,
            show_statistics,
            concurrency,
            single_version_file,
            generate_display_trait,
            docs_rs_features,
            disable_format,
            split_build_rs,
            extra_versions,
            lib_version_overrides,
            feature_dependencies,
        })
    }

    pub fn library_full_name(&self) -> String {
        format!("{}-{}", self.library_name, self.library_version)
    }

    pub fn filter_version(&self, version: Option<Version>) -> Option<Version> {
        version.and_then(|v| {
            if v > self.min_cfg_version {
                Some(v)
            } else {
                None
            }
        })
    }

    pub fn resolve_type_ids(&mut self, library: &Library) {
        gobjects::resolve_type_ids(&mut self.objects, library)
    }

    pub fn check_disable_format(&mut self) {
        if !self.disable_format && !crate::fmt::check_fmt() {
            warn!("Formatter not found, options.disable_format set to true");
            self.disable_format = true;
        }
    }
}

fn read_toml<P: AsRef<Path>>(filename: P) -> Result<toml::Value, String> {
    if !filename.as_ref().is_file() {
        return Err("Config don't exists or not file".to_owned());
    }
    let mut input = String::new();
    match File::open(&filename) {
        Ok(mut f) => {
            if let Err(e) = f.read_to_string(&mut input) {
                return Err(format!(
                    "read_to_string failed on \"{}\": {}",
                    filename.as_ref().display(),
                    e
                ));
            }

            match toml::from_str(&input) {
                Ok(toml) => Ok(toml),
                Err(e) => Err(format!(
                    "Invalid toml format in \"{}\": {}",
                    filename.as_ref().display(),
                    e
                )),
            }
        }
        Err(e) => Err(format!(
            "Cannot open file \"{}\": {}",
            filename.as_ref().display(),
            e
        )),
    }
}

fn make_single_version_file(configured: Option<&str>, target_path: &Path) -> PathBuf {
    let file_dir = match configured {
        None | Some("") => target_path.join("src").join("auto"),
        Some(path) => target_path.join(path),
    };

    if file_dir.extension().is_some() {
        file_dir
    } else {
        file_dir.join("versions.txt")
    }
}

fn read_crate_name_overrides(toml: &toml::Value) -> HashMap<String, String> {
    let mut overrides = HashMap::new();
    if let Some(a) = toml
        .lookup("crate_name_overrides")
        .and_then(toml::Value::as_table)
    {
        for (key, value) in a {
            if let Some(s) = value.as_str() {
                overrides.insert(key.clone(), s.to_string());
            }
        }
    };
    overrides
}

fn read_extra_versions(toml: &toml::Value) -> Result<Vec<Version>, String> {
    match toml.lookup("options.extra_versions") {
        Some(a) => a
            .as_result_vec("options.extra_versions")?
            .iter()
            .map(|v| {
                v.as_str().ok_or_else(|| {
                    "options.extra_versions expected to be array of string".to_string()
                })
            })
            .map(|s| s.and_then(str::parse))
            .collect(),
        None => Ok(Vec::new()),
    }
}

fn read_lib_version_overrides(toml: &toml::Value) -> Result<HashMap<Version, Version>, String> {
    let v = match toml.lookup("lib_version_overrides") {
        Some(a) => a.as_result_vec("lib_version_overrides")?,
        None => return Ok(Default::default()),
    };

    let mut map = HashMap::with_capacity(v.len());
    for o in v {
        let cfg = o
            .lookup_str("version", "No version in lib_version_overrides")?
            .parse()?;
        let lib = o
            .lookup_str("lib_version", "No lib_version in lib_version_overrides")?
            .parse()?;
        map.insert(cfg, lib);
    }

    Ok(map)
}

fn read_feature_dependencies(toml: &toml::Value) -> Result<HashMap<Version, Vec<String>>, String> {
    let v = match toml.lookup("feature_dependencies") {
        Some(a) => a.as_result_vec("feature_dependencies")?,
        None => return Ok(Default::default()),
    };

    let mut map = HashMap::with_capacity(v.len());
    for o in v {
        let cfg = o
            .lookup_str("version", "No version in feature_dependencies")?
            .parse()?;
        let dependencies: Result<Vec<String>, String> = o
            .lookup_vec("dependencies", "No dependencies in feature_dependencies")?
            .iter()
            .map(|v| {
                v.as_str()
                    .ok_or_else(|| {
                        "feature_dependencies.dependencies expected to be array of string"
                            .to_string()
                    })
                    .map(str::to_owned)
            })
            .collect();
        map.insert(cfg, dependencies?);
    }

    Ok(map)
}

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

    #[test]
    fn test_make_single_version_file() {
        let target_path = Path::new("/tmp/glib");
        assert_eq!(
            make_single_version_file(None, &target_path),
            PathBuf::from("/tmp/glib/src/auto/versions.txt")
        );
        assert_eq!(
            make_single_version_file(Some(""), &target_path),
            PathBuf::from("/tmp/glib/src/auto/versions.txt")
        );
        assert_eq!(
            make_single_version_file(Some("src"), &target_path),
            PathBuf::from("/tmp/glib/src/versions.txt")
        );
        assert_eq!(
            make_single_version_file(Some("src/vers.txt"), &target_path),
            PathBuf::from("/tmp/glib/src/vers.txt")
        );
        assert_eq!(
            make_single_version_file(Some("."), &target_path),
            PathBuf::from("/tmp/glib/versions.txt")
        );
        assert_eq!(
            make_single_version_file(Some("./_vers.dat"), &target_path),
            PathBuf::from("/tmp/glib/_vers.dat")
        );
    }
}
<|endoftext|>


<commit_before>extern crate yaml_rust;
use self::yaml_rust::{YamlLoader, Yaml};
use command;
use file;

pub struct Configuration {
    pub commands: Vec<command::Command>,
    pub packages: Vec<String>,
    pub files: Vec<file::FileResource>,
    pub install_command: Option<String>
}

fn convert_yaml_string(yaml_str: &yaml_rust::yaml::Yaml) -> String {
    match yaml_str.as_str() {
        Some(s) => {
            return s.to_string()
        },
        None => {
            return String::new();
        }
    }
}

fn extract_file_resources(file_list: &yaml_rust::yaml::Yaml) -> Vec<file::FileResource> {
    let mut file_resources = Vec::new();
    println!("{:?}", file_list);
    match file_list.as_vec() {
        Some(lst) => {
            file_resources = lst.iter()
                .map(|e| file::FileResource{
                    content: convert_yaml_string(e.as_hash().unwrap().get(&Yaml::from_str("content")).unwrap()),
                    path: convert_yaml_string(e.as_hash().unwrap().get(&Yaml::from_str("path")).unwrap())
                })
                .collect::<Vec<_>>()
        }
        None => {}
    }
    return file_resources;
}

pub fn from_yaml(yaml_file: String) -> Configuration {
    let docs = YamlLoader::load_from_str(&yaml_file).unwrap();
    let doc = &docs[0];

    let default_node = doc.as_hash().unwrap().get(&Yaml::from_str("default")).unwrap();
    let empty_list = Yaml::Array(Vec::new());
    let command_list = default_node.as_hash().unwrap().get(&Yaml::from_str("commands")).unwrap_or(&empty_list);
    let package_list = default_node.as_hash().unwrap().get(&Yaml::from_str("packages")).unwrap_or(&empty_list);
    let yaml_install_command = default_node.as_hash().unwrap().get(&Yaml::from_str("package_install_cmd"));
    let file_list = default_node.as_hash().unwrap().get(&Yaml::from_str("files")).unwrap_or(&empty_list);
    let mut yaml_commands = Vec::new();
    let mut yaml_packages = Vec::new();

    match command_list.as_vec() {
        Some(lst) => {
            yaml_commands = lst.iter()
                 .map(|e| command::parse(e.as_str().expect("expected string").to_string()))
                 .collect::<Vec<_>>()
        },
        None => {}
    }

    match package_list.as_vec() {
        Some(lst) => {
            yaml_packages = lst.iter()
                .map(|e| e.as_str().expect("expected string").to_string())
                .collect::<Vec<_>>()
        },
        None => { }
    }

    let file_resources = extract_file_resources(file_list);

    let mut install_cmd = None;

    match yaml_install_command {
        Some(cmd) => {
            let s = cmd.as_str().unwrap();
            install_cmd = Some(s.to_string())
        },
        None => {}
    }

    Configuration {
        commands: yaml_commands,
        packages: yaml_packages,
        files: file_resources,
        install_command: install_cmd
    }
}
<commit_msg>Remove debug output<commit_after>extern crate yaml_rust;
use self::yaml_rust::{YamlLoader, Yaml};
use command;
use file;

pub struct Configuration {
    pub commands: Vec<command::Command>,
    pub packages: Vec<String>,
    pub files: Vec<file::FileResource>,
    pub install_command: Option<String>
}

fn convert_yaml_string(yaml_str: &yaml_rust::yaml::Yaml) -> String {
    match yaml_str.as_str() {
        Some(s) => {
            return s.to_string()
        },
        None => {
            return String::new();
        }
    }
}

fn extract_file_resources(file_list: &yaml_rust::yaml::Yaml) -> Vec<file::FileResource> {
    let mut file_resources = Vec::new();
    match file_list.as_vec() {
        Some(lst) => {
            file_resources = lst.iter()
                .map(|e| file::FileResource{
                    content: convert_yaml_string(e.as_hash().unwrap().get(&Yaml::from_str("content")).unwrap()),
                    path: convert_yaml_string(e.as_hash().unwrap().get(&Yaml::from_str("path")).unwrap())
                })
                .collect::<Vec<_>>()
        }
        None => {}
    }
    return file_resources;
}

pub fn from_yaml(yaml_file: String) -> Configuration {
    let docs = YamlLoader::load_from_str(&yaml_file).unwrap();
    let doc = &docs[0];

    let default_node = doc.as_hash().unwrap().get(&Yaml::from_str("default")).unwrap();
    let empty_list = Yaml::Array(Vec::new());
    let command_list = default_node.as_hash().unwrap().get(&Yaml::from_str("commands")).unwrap_or(&empty_list);
    let package_list = default_node.as_hash().unwrap().get(&Yaml::from_str("packages")).unwrap_or(&empty_list);
    let yaml_install_command = default_node.as_hash().unwrap().get(&Yaml::from_str("package_install_cmd"));
    let file_list = default_node.as_hash().unwrap().get(&Yaml::from_str("files")).unwrap_or(&empty_list);
    let mut yaml_commands = Vec::new();
    let mut yaml_packages = Vec::new();

    match command_list.as_vec() {
        Some(lst) => {
            yaml_commands = lst.iter()
                 .map(|e| command::parse(e.as_str().expect("expected string").to_string()))
                 .collect::<Vec<_>>()
        },
        None => {}
    }

    match package_list.as_vec() {
        Some(lst) => {
            yaml_packages = lst.iter()
                .map(|e| e.as_str().expect("expected string").to_string())
                .collect::<Vec<_>>()
        },
        None => { }
    }

    let file_resources = extract_file_resources(file_list);

    let mut install_cmd = None;

    match yaml_install_command {
        Some(cmd) => {
            let s = cmd.as_str().unwrap();
            install_cmd = Some(s.to_string())
        },
        None => {}
    }

    Configuration {
        commands: yaml_commands,
        packages: yaml_packages,
        files: file_resources,
        install_command: install_cmd
    }
}
<|endoftext|>


<commit_before>use super::super::award::*;
use super::*;

use diesel::prelude::*;
use diesel::sql_types::{Bool, Double, Text};

use crate::contest::api::ApiContext;
use crate::contest::contest_submission::Submission;
use juniper::FieldResult;
use schema::awards;

#[derive(Insertable)]
#[table_name = "awards"]
pub struct AwardInput<'a> {
    pub kind: &'a str,
    pub submission_id: &'a str,
    pub award_name: &'a str,
    pub value: f64,
}

#[derive(Queryable, QueryableByName)]
pub struct AwardData {
    #[allow(dead_code)]
    #[sql_type = "Text"]
    kind: String,

    /// Id of the submission
    #[allow(dead_code)]
    #[sql_type = "Text"]
    submission_id: String,

    /// Name of the award
    #[sql_type = "Text"]
    award_name: String,

    #[sql_type = "Double"]
    value: f64,
}

pub struct SubmissionAward<'a> {
    context: &'a ApiContext<'a>,
    data: AwardData,
}

impl SubmissionAward<'_> {
    const BY_USER_AND_PROBLEM_SQL: &'static str = "
        SELECT sc.kind, sc.award_name, MAX(sc.value) as value, (
            SELECT s.id
            FROM submissions s JOIN awards sci ON s.id = sci.submission_id
            WHERE sci.value = value AND sci.kind = sc.kind AND sci.award_name = sc.award_name
            ORDER BY s.created_at DESC
            LIMIT 1
        ) as submission_id
        FROM awards sc JOIN submissions s ON sc.submission_id = s.id
        GROUP BY s.problem_name, sc.award_name, s.user_id
    ";

    pub fn list_by_user_and_problem<'a>(
        context: &'a ApiContext,
    ) -> FieldResult<Vec<SubmissionAward<'a>>> {
        Ok(diesel::sql_query(Self::BY_USER_AND_PROBLEM_SQL)
            .load::<AwardData>(&context.database)?
            .into_iter()
            .map(|data| SubmissionAward { context, data })
            .collect())
    }

    /// Get the best score award for (user, problem)
    pub fn by_user_and_problem<'a>(
        context: &'a ApiContext,
        user_id: &str,
        problem_name: &str,
    ) -> FieldResult<Vec<SubmissionAward<'a>>> {
        Ok(diesel::sql_query(format!(
            "
                {}
                HAVING s.problem_name = ? AND s.user_id = ?
            ",
            Self::BY_USER_AND_PROBLEM_SQL
        ))
        .bind::<Text, _>(problem_name)
        .bind::<Text, _>(user_id)
        .load::<AwardData>(&context.database)?
        .into_iter()
        .map(|data| SubmissionAward { context, data })
        .collect())
    }

    /// Get the awards of (user, problem, submission)
    pub fn of_submission<'a>(
        context: &'a ApiContext,
        submission_id: &str,
    ) -> FieldResult<Vec<SubmissionAward<'a>>> {
        Ok(awards::table
            .filter(awards::dsl::submission_id.eq(submission_id))
            .load(&context.database)?
            .into_iter()
            .map(|data| SubmissionAward { context, data })
            .collect())
    }

    pub fn submission_id(&self) -> &String {
        &self.data.submission_id
    }
}

#[juniper_ext::graphql]
impl SubmissionAward<'_> {
    fn submission(&self) -> FieldResult<Submission> {
        Submission::by_id(&self.context, &self.data.submission_id)
    }

    /// Name of the award
    fn award_name(&self) -> AwardName {
        AwardName(self.data.award_name.clone())
    }

    fn value(&self) -> AwardValue {
        match self.data.kind.as_ref() {
            "SCORE" => AwardValue::Score(ScoreAwardValue {
                score: Score(self.data.value),
            }),
            "BADGE" => AwardValue::Badge(BadgeAwardValue {
                badge: self.data.value == 1f64,
            }),
            _ => unreachable!(),
        }
    }
}

#[derive(juniper_ext::GraphQLUnionFromEnum)]
pub enum AwardValue {
    Score(ScoreAwardValue),
    Badge(BadgeAwardValue),
}

#[derive(juniper::GraphQLObject)]
pub struct ScoreAwardValue {
    pub score: Score,
}

#[derive(juniper::GraphQLObject)]
pub struct BadgeAwardValue {
    pub badge: bool,
}
<commit_msg>Fix error in award query with multiple users<commit_after>use super::super::award::*;
use super::*;

use diesel::prelude::*;
use diesel::sql_types::{Bool, Double, Text};

use crate::contest::api::ApiContext;
use crate::contest::contest_submission::Submission;
use juniper::FieldResult;
use schema::awards;

#[derive(Insertable)]
#[table_name = "awards"]
pub struct AwardInput<'a> {
    pub kind: &'a str,
    pub submission_id: &'a str,
    pub award_name: &'a str,
    pub value: f64,
}

#[derive(Queryable, QueryableByName)]
pub struct AwardData {
    #[allow(dead_code)]
    #[sql_type = "Text"]
    kind: String,

    /// Id of the submission
    #[allow(dead_code)]
    #[sql_type = "Text"]
    submission_id: String,

    /// Name of the award
    #[sql_type = "Text"]
    award_name: String,

    #[sql_type = "Double"]
    value: f64,
}

pub struct SubmissionAward<'a> {
    context: &'a ApiContext<'a>,
    data: AwardData,
}

impl SubmissionAward<'_> {
    const BY_USER_AND_PROBLEM_SQL: &'static str = "
        SELECT a.kind, a.award_name, MAX(a.value) as value, (
            SELECT s.id
            FROM submissions s2 JOIN awards a2 ON s2.id = a2.submission_id
            WHERE a2.value = value AND a2.kind = a.kind AND a2.award_name = a.award_name
                AND s2.problem_name = s.problem_name AND s2.user_id = s.user_id
            ORDER BY s2.created_at DESC
            LIMIT 1
        ) as submission_id
        FROM awards a JOIN submissions s ON a.submission_id = s.id
        GROUP BY s.problem_name, a.award_name, s.user_id
    ";

    pub fn list_by_user_and_problem<'a>(
        context: &'a ApiContext,
    ) -> FieldResult<Vec<SubmissionAward<'a>>> {
        Ok(diesel::sql_query(Self::BY_USER_AND_PROBLEM_SQL)
            .load::<AwardData>(&context.database)?
            .into_iter()
            .map(|data| SubmissionAward { context, data })
            .collect())
    }

    /// Get the best score award for (user, problem)
    pub fn by_user_and_problem<'a>(
        context: &'a ApiContext,
        user_id: &str,
        problem_name: &str,
    ) -> FieldResult<Vec<SubmissionAward<'a>>> {
        Ok(diesel::sql_query(format!(
            "
                {}
                HAVING s.problem_name = ? AND s.user_id = ?
            ",
            Self::BY_USER_AND_PROBLEM_SQL
        ))
        .bind::<Text, _>(problem_name)
        .bind::<Text, _>(user_id)
        .load::<AwardData>(&context.database)?
        .into_iter()
        .map(|data| SubmissionAward { context, data })
        .collect())
    }

    /// Get the awards of (user, problem, submission)
    pub fn of_submission<'a>(
        context: &'a ApiContext,
        submission_id: &str,
    ) -> FieldResult<Vec<SubmissionAward<'a>>> {
        Ok(awards::table
            .filter(awards::dsl::submission_id.eq(submission_id))
            .load(&context.database)?
            .into_iter()
            .map(|data| SubmissionAward { context, data })
            .collect())
    }

    pub fn submission_id(&self) -> &String {
        &self.data.submission_id
    }
}

#[juniper_ext::graphql]
impl SubmissionAward<'_> {
    fn submission(&self) -> FieldResult<Submission> {
        Submission::by_id(&self.context, &self.data.submission_id)
    }

    /// Name of the award
    fn award_name(&self) -> AwardName {
        AwardName(self.data.award_name.clone())
    }

    fn value(&self) -> AwardValue {
        match self.data.kind.as_ref() {
            "SCORE" => AwardValue::Score(ScoreAwardValue {
                score: Score(self.data.value),
            }),
            "BADGE" => AwardValue::Badge(BadgeAwardValue {
                badge: self.data.value == 1f64,
            }),
            _ => unreachable!(),
        }
    }
}

#[derive(juniper_ext::GraphQLUnionFromEnum)]
pub enum AwardValue {
    Score(ScoreAwardValue),
    Badge(BadgeAwardValue),
}

#[derive(juniper::GraphQLObject)]
pub struct ScoreAwardValue {
    pub score: Score,
}

#[derive(juniper::GraphQLObject)]
pub struct BadgeAwardValue {
    pub badge: bool,
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::context::LayoutContext;
use crate::dom_traversal::{Contents, NodeExt};
use crate::flow::construct::ContainsFloats;
use crate::flow::float::FloatBox;
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Fragment;
use crate::geom::flow_relative::Vec2;
use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSize};
use crate::positioned::AbsolutelyPositionedBox;
use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
use crate::sizing::ContentSizesRequest;
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside};
use crate::DefiniteContainingBlock;
use app_units::Au;
use euclid::default::{Point2D, Rect, Size2D};
use gfx_traits::print_tree::PrintTree;
use script_layout_interface::wrapper_traits::LayoutNode;
use servo_arc::Arc;
use style::dom::OpaqueNode;
use style::properties::{style_structs, ComputedValues};
use style::values::computed::Length;
use style_traits::CSSPixel;

pub struct BoxTreeRoot(BlockFormattingContext);

pub struct FragmentTreeRoot {
    /// The children of the root of the fragment tree.
    children: Vec<Fragment>,

    /// The scrollable overflow of the root of the fragment tree.
    scrollable_overflow: PhysicalRect<Length>,

    /// The containing block used in the layout of this fragment tree.
    initial_containing_block: PhysicalRect<Length>,
}

impl BoxTreeRoot {
    pub fn construct<'dom, Node>(context: &LayoutContext, root_element: Node) -> Self
    where
        Node: 'dom + Copy + LayoutNode + Send + Sync,
    {
        let (contains_floats, boxes) = construct_for_root_element(&context, root_element);
        Self(BlockFormattingContext {
            contains_floats: contains_floats == ContainsFloats::Yes,
            contents: BlockContainer::BlockLevelBoxes(boxes),
        })
    }
}

fn construct_for_root_element<'dom>(
    context: &LayoutContext,
    root_element: impl NodeExt<'dom>,
) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) {
    let style = root_element.style(context);
    let replaced = ReplacedContent::for_element(root_element);
    let box_style = style.get_box();

    let display_inside = match Display::from(box_style.display) {
        Display::None => return (ContainsFloats::No, Vec::new()),
        Display::Contents if replaced.is_some() => {
            // 'display: contents' computes to 'none' for replaced elements
            return (ContainsFloats::No, Vec::new());
        },
        // https://drafts.csswg.org/css-display-3/#transformations
        Display::Contents => DisplayInside::Flow,
        // The root element is blockified, ignore DisplayOutside
        Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside,
    };

    let contents = replaced.map_or(Contents::OfElement, Contents::Replaced);
    if box_style.position.is_absolutely_positioned() {
        (
            ContainsFloats::No,
            vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
                AbsolutelyPositionedBox::construct(
                    context,
                    root_element,
                    style,
                    display_inside,
                    contents,
                ),
            ))],
        )
    } else if box_style.float.is_floating() {
        (
            ContainsFloats::Yes,
            vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(
                FloatBox::construct(context, root_element, style, display_inside, contents),
            ))],
        )
    } else {
        (
            ContainsFloats::No,
            vec![Arc::new(BlockLevelBox::Independent(
                IndependentFormattingContext::construct(
                    context,
                    root_element,
                    style,
                    display_inside,
                    contents,
                    ContentSizesRequest::None,
                ),
            ))],
        )
    }
}

impl BoxTreeRoot {
    pub fn layout(
        &self,
        layout_context: &LayoutContext,
        viewport: euclid::Size2D<f32, CSSPixel>,
    ) -> FragmentTreeRoot {
        let style = ComputedValues::initial_values();

        // FIXME: use the document’s mode:
        // https://drafts.csswg.org/css-writing-modes/#principal-flow
        let physical_containing_block = PhysicalRect::new(
            PhysicalPoint::zero(),
            PhysicalSize::new(Length::new(viewport.width), Length::new(viewport.height)),
        );
        let initial_containing_block = DefiniteContainingBlock {
            size: Vec2 {
                inline: physical_containing_block.size.width,
                block: physical_containing_block.size.height,
            },
            style,
        };

        let dummy_tree_rank = 0;
        let mut positioning_context = PositioningContext::new_for_initial_containing_block();
        let mut independent_layout = self.0.layout(
            layout_context,
            &mut positioning_context,
            &(&initial_containing_block).into(),
            dummy_tree_rank,
        );

        positioning_context.layout_in_initial_containing_block(
            layout_context,
            &initial_containing_block,
            &mut independent_layout.fragments,
        );

        let scrollable_overflow =
            independent_layout
                .fragments
                .iter()
                .fold(PhysicalRect::zero(), |acc, child| {
                    let child_overflow = child.scrollable_overflow();

                    // https://drafts.csswg.org/css-overflow/#scrolling-direction
                    // We want to clip scrollable overflow on box-start and inline-start
                    // sides of the scroll container.
                    //
                    // FIXME(mrobinson, bug 25564): This should take into account writing
                    // mode.
                    let child_overflow = PhysicalRect::new(
                        euclid::Point2D::zero(),
                        euclid::Size2D::new(
                            child_overflow.size.width + child_overflow.origin.x,
                            child_overflow.size.height + child_overflow.origin.y,
                        ),
                    );
                    acc.union(&child_overflow)
                });

        FragmentTreeRoot {
            children: independent_layout.fragments,
            scrollable_overflow,
            initial_containing_block: physical_containing_block,
        }
    }
}

impl FragmentTreeRoot {
    pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) {
        for fragment in &self.children {
            fragment.build_display_list(builder, &self.initial_containing_block)
        }
    }

    pub fn print(&self) {
        let mut print_tree = PrintTree::new("Fragment Tree".to_string());
        for fragment in &self.children {
            fragment.print(&mut print_tree);
        }
    }

    pub fn scrollable_overflow(&self) -> webrender_api::units::LayoutSize {
        webrender_api::units::LayoutSize::from_untyped(Size2D::new(
            self.scrollable_overflow.size.width.px(),
            self.scrollable_overflow.size.height.px(),
        ))
    }

    fn iterate_through_fragments<F>(&self, process_func: &mut F)
    where
        F: FnMut(&Fragment, &PhysicalRect<Length>) -> bool,
    {
        fn do_iteration<M>(
            fragment: &Fragment,
            containing_block: &PhysicalRect<Length>,
            process_func: &mut M,
        ) -> bool
        where
            M: FnMut(&Fragment, &PhysicalRect<Length>) -> bool,
        {
            if !process_func(fragment, containing_block) {
                return false;
            }

            match fragment {
                Fragment::Box(fragment) => {
                    let new_containing_block = fragment
                        .content_rect
                        .to_physical(fragment.style.writing_mode, containing_block)
                        .translate(containing_block.origin.to_vector());
                    for child in &fragment.children {
                        do_iteration(child, &new_containing_block, process_func);
                    }
                },
                Fragment::Anonymous(fragment) => {
                    let new_containing_block = fragment
                        .rect
                        .to_physical(fragment.mode, containing_block)
                        .translate(containing_block.origin.to_vector());
                    for child in &fragment.children {
                        do_iteration(child, &new_containing_block, process_func);
                    }
                },
                _ => {},
            }

            true
        }

        for child in &self.children {
            if !do_iteration(child, &self.initial_containing_block, process_func) {
                break;
            }
        }
    }

    pub fn get_content_box_for_node(&self, requested_node: OpaqueNode) -> Rect<Au> {
        let mut rect = PhysicalRect::zero();
        let mut process = |fragment: &Fragment, containing_block: &PhysicalRect<Length>| {
            let fragment_relative_rect = match fragment {
                Fragment::Box(fragment) if fragment.tag == requested_node => fragment
                    .border_rect()
                    .to_physical(fragment.style.writing_mode, &containing_block),
                Fragment::Text(fragment) if fragment.tag == requested_node => fragment
                    .rect
                    .to_physical(fragment.parent_style.writing_mode, &containing_block),
                Fragment::Box(_) |
                Fragment::Text(_) |
                Fragment::Image(_) |
                Fragment::Anonymous(_) => return true,
            };

            rect = fragment_relative_rect
                .translate(containing_block.origin.to_vector())
                .union(&rect);
            return true;
        };

        self.iterate_through_fragments(&mut process);

        Rect::new(
            Point2D::new(
                Au::from_f32_px(rect.origin.x.px()),
                Au::from_f32_px(rect.origin.y.px()),
            ),
            Size2D::new(
                Au::from_f32_px(rect.size.width.px()),
                Au::from_f32_px(rect.size.height.px()),
            ),
        )
    }

    pub fn get_border_dimensions_for_node(&self, requested_node: OpaqueNode) -> Rect<i32> {
        let mut border_dimensions = Rect::zero();
        let mut process = |fragment: &Fragment, containing_block: &PhysicalRect<Length>| {
            let (style, padding_rect) = match fragment {
                Fragment::Box(fragment) if fragment.tag == requested_node => {
                    (&fragment.style, fragment.padding_rect())
                },
                Fragment::Box(_) |
                Fragment::Text(_) |
                Fragment::Image(_) |
                Fragment::Anonymous(_) => return true,
            };

            // https://drafts.csswg.org/cssom-view/#dom-element-clienttop
            // " If the element has no associated CSS layout box or if the
            //   CSS layout box is inline, return zero." For this check we
            // also explicitly ignore the list item portion of the display
            // style.
            let display = &style.get_box().display;
            if display.inside() == style::values::specified::box_::DisplayInside::Flow &&
                display.outside() == style::values::specified::box_::DisplayOutside::Inline
            {
                return false;
            }

            let style_structs::Border {
                border_top_width: top_width,
                border_left_width: left_width,
                ..
            } = *style.get_border();

            let padding_rect = padding_rect.to_physical(style.writing_mode, &containing_block);
            border_dimensions.size.width = padding_rect.size.width.px() as i32;
            border_dimensions.size.height = padding_rect.size.height.px() as i32;
            border_dimensions.origin.y = top_width.px() as i32;
            border_dimensions.origin.x = left_width.px() as i32;

            false
        };

        self.iterate_through_fragments(&mut process);

        border_dimensions
    }
}
<commit_msg>Exit iterate_through_fragments through all recursion levels when the callback says so<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::context::LayoutContext;
use crate::dom_traversal::{Contents, NodeExt};
use crate::flow::construct::ContainsFloats;
use crate::flow::float::FloatBox;
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Fragment;
use crate::geom::flow_relative::Vec2;
use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSize};
use crate::positioned::AbsolutelyPositionedBox;
use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
use crate::sizing::ContentSizesRequest;
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside};
use crate::DefiniteContainingBlock;
use app_units::Au;
use euclid::default::{Point2D, Rect, Size2D};
use gfx_traits::print_tree::PrintTree;
use script_layout_interface::wrapper_traits::LayoutNode;
use servo_arc::Arc;
use style::dom::OpaqueNode;
use style::properties::{style_structs, ComputedValues};
use style::values::computed::Length;
use style_traits::CSSPixel;

pub struct BoxTreeRoot(BlockFormattingContext);

pub struct FragmentTreeRoot {
    /// The children of the root of the fragment tree.
    children: Vec<Fragment>,

    /// The scrollable overflow of the root of the fragment tree.
    scrollable_overflow: PhysicalRect<Length>,

    /// The containing block used in the layout of this fragment tree.
    initial_containing_block: PhysicalRect<Length>,
}

impl BoxTreeRoot {
    pub fn construct<'dom, Node>(context: &LayoutContext, root_element: Node) -> Self
    where
        Node: 'dom + Copy + LayoutNode + Send + Sync,
    {
        let (contains_floats, boxes) = construct_for_root_element(&context, root_element);
        Self(BlockFormattingContext {
            contains_floats: contains_floats == ContainsFloats::Yes,
            contents: BlockContainer::BlockLevelBoxes(boxes),
        })
    }
}

fn construct_for_root_element<'dom>(
    context: &LayoutContext,
    root_element: impl NodeExt<'dom>,
) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) {
    let style = root_element.style(context);
    let replaced = ReplacedContent::for_element(root_element);
    let box_style = style.get_box();

    let display_inside = match Display::from(box_style.display) {
        Display::None => return (ContainsFloats::No, Vec::new()),
        Display::Contents if replaced.is_some() => {
            // 'display: contents' computes to 'none' for replaced elements
            return (ContainsFloats::No, Vec::new());
        },
        // https://drafts.csswg.org/css-display-3/#transformations
        Display::Contents => DisplayInside::Flow,
        // The root element is blockified, ignore DisplayOutside
        Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside,
    };

    let contents = replaced.map_or(Contents::OfElement, Contents::Replaced);
    if box_style.position.is_absolutely_positioned() {
        (
            ContainsFloats::No,
            vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
                AbsolutelyPositionedBox::construct(
                    context,
                    root_element,
                    style,
                    display_inside,
                    contents,
                ),
            ))],
        )
    } else if box_style.float.is_floating() {
        (
            ContainsFloats::Yes,
            vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(
                FloatBox::construct(context, root_element, style, display_inside, contents),
            ))],
        )
    } else {
        (
            ContainsFloats::No,
            vec![Arc::new(BlockLevelBox::Independent(
                IndependentFormattingContext::construct(
                    context,
                    root_element,
                    style,
                    display_inside,
                    contents,
                    ContentSizesRequest::None,
                ),
            ))],
        )
    }
}

impl BoxTreeRoot {
    pub fn layout(
        &self,
        layout_context: &LayoutContext,
        viewport: euclid::Size2D<f32, CSSPixel>,
    ) -> FragmentTreeRoot {
        let style = ComputedValues::initial_values();

        // FIXME: use the document’s mode:
        // https://drafts.csswg.org/css-writing-modes/#principal-flow
        let physical_containing_block = PhysicalRect::new(
            PhysicalPoint::zero(),
            PhysicalSize::new(Length::new(viewport.width), Length::new(viewport.height)),
        );
        let initial_containing_block = DefiniteContainingBlock {
            size: Vec2 {
                inline: physical_containing_block.size.width,
                block: physical_containing_block.size.height,
            },
            style,
        };

        let dummy_tree_rank = 0;
        let mut positioning_context = PositioningContext::new_for_initial_containing_block();
        let mut independent_layout = self.0.layout(
            layout_context,
            &mut positioning_context,
            &(&initial_containing_block).into(),
            dummy_tree_rank,
        );

        positioning_context.layout_in_initial_containing_block(
            layout_context,
            &initial_containing_block,
            &mut independent_layout.fragments,
        );

        let scrollable_overflow =
            independent_layout
                .fragments
                .iter()
                .fold(PhysicalRect::zero(), |acc, child| {
                    let child_overflow = child.scrollable_overflow();

                    // https://drafts.csswg.org/css-overflow/#scrolling-direction
                    // We want to clip scrollable overflow on box-start and inline-start
                    // sides of the scroll container.
                    //
                    // FIXME(mrobinson, bug 25564): This should take into account writing
                    // mode.
                    let child_overflow = PhysicalRect::new(
                        euclid::Point2D::zero(),
                        euclid::Size2D::new(
                            child_overflow.size.width + child_overflow.origin.x,
                            child_overflow.size.height + child_overflow.origin.y,
                        ),
                    );
                    acc.union(&child_overflow)
                });

        FragmentTreeRoot {
            children: independent_layout.fragments,
            scrollable_overflow,
            initial_containing_block: physical_containing_block,
        }
    }
}

impl FragmentTreeRoot {
    pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) {
        for fragment in &self.children {
            fragment.build_display_list(builder, &self.initial_containing_block)
        }
    }

    pub fn print(&self) {
        let mut print_tree = PrintTree::new("Fragment Tree".to_string());
        for fragment in &self.children {
            fragment.print(&mut print_tree);
        }
    }

    pub fn scrollable_overflow(&self) -> webrender_api::units::LayoutSize {
        webrender_api::units::LayoutSize::from_untyped(Size2D::new(
            self.scrollable_overflow.size.width.px(),
            self.scrollable_overflow.size.height.px(),
        ))
    }

    fn iterate_through_fragments<F>(&self, process_func: &mut F)
    where
        F: FnMut(&Fragment, &PhysicalRect<Length>) -> bool,
    {
        fn do_iteration<M>(
            fragment: &Fragment,
            containing_block: &PhysicalRect<Length>,
            process_func: &mut M,
        ) -> bool
        where
            M: FnMut(&Fragment, &PhysicalRect<Length>) -> bool,
        {
            if !process_func(fragment, containing_block) {
                return false;
            }

            match fragment {
                Fragment::Box(fragment) => {
                    let new_containing_block = fragment
                        .content_rect
                        .to_physical(fragment.style.writing_mode, containing_block)
                        .translate(containing_block.origin.to_vector());
                    for child in &fragment.children {
                        if !do_iteration(child, &new_containing_block, process_func) {
                            return false;
                        }
                    }
                },
                Fragment::Anonymous(fragment) => {
                    let new_containing_block = fragment
                        .rect
                        .to_physical(fragment.mode, containing_block)
                        .translate(containing_block.origin.to_vector());
                    for child in &fragment.children {
                        if !do_iteration(child, &new_containing_block, process_func) {
                            return false;
                        }
                    }
                },
                _ => {},
            }

            true
        }

        for child in &self.children {
            if !do_iteration(child, &self.initial_containing_block, process_func) {
                break;
            }
        }
    }

    pub fn get_content_box_for_node(&self, requested_node: OpaqueNode) -> Rect<Au> {
        let mut rect = PhysicalRect::zero();
        let mut process = |fragment: &Fragment, containing_block: &PhysicalRect<Length>| {
            let fragment_relative_rect = match fragment {
                Fragment::Box(fragment) if fragment.tag == requested_node => fragment
                    .border_rect()
                    .to_physical(fragment.style.writing_mode, &containing_block),
                Fragment::Text(fragment) if fragment.tag == requested_node => fragment
                    .rect
                    .to_physical(fragment.parent_style.writing_mode, &containing_block),
                Fragment::Box(_) |
                Fragment::Text(_) |
                Fragment::Image(_) |
                Fragment::Anonymous(_) => return true,
            };

            rect = fragment_relative_rect
                .translate(containing_block.origin.to_vector())
                .union(&rect);
            return true;
        };

        self.iterate_through_fragments(&mut process);

        Rect::new(
            Point2D::new(
                Au::from_f32_px(rect.origin.x.px()),
                Au::from_f32_px(rect.origin.y.px()),
            ),
            Size2D::new(
                Au::from_f32_px(rect.size.width.px()),
                Au::from_f32_px(rect.size.height.px()),
            ),
        )
    }

    pub fn get_border_dimensions_for_node(&self, requested_node: OpaqueNode) -> Rect<i32> {
        let mut border_dimensions = Rect::zero();
        let mut process = |fragment: &Fragment, containing_block: &PhysicalRect<Length>| {
            let (style, padding_rect) = match fragment {
                Fragment::Box(fragment) if fragment.tag == requested_node => {
                    (&fragment.style, fragment.padding_rect())
                },
                Fragment::Box(_) |
                Fragment::Text(_) |
                Fragment::Image(_) |
                Fragment::Anonymous(_) => return true,
            };

            // https://drafts.csswg.org/cssom-view/#dom-element-clienttop
            // " If the element has no associated CSS layout box or if the
            //   CSS layout box is inline, return zero." For this check we
            // also explicitly ignore the list item portion of the display
            // style.
            let display = &style.get_box().display;
            if display.inside() == style::values::specified::box_::DisplayInside::Flow &&
                display.outside() == style::values::specified::box_::DisplayOutside::Inline
            {
                return false;
            }

            let style_structs::Border {
                border_top_width: top_width,
                border_left_width: left_width,
                ..
            } = *style.get_border();

            let padding_rect = padding_rect.to_physical(style.writing_mode, &containing_block);
            border_dimensions.size.width = padding_rect.size.width.px() as i32;
            border_dimensions.size.height = padding_rect.size.height.px() as i32;
            border_dimensions.origin.y = top_width.px() as i32;
            border_dimensions.origin.x = left_width.px() as i32;

            false
        };

        self.iterate_through_fragments(&mut process);

        border_dimensions
    }
}
<|endoftext|>


<commit_before>use diesel::expression::sql;
use diesel::pg::PgConnection;
use diesel::types::Bool;
use diesel::{Connection, select, LoadDsl};

pub struct Database {
    url: String
}

impl Database {
    pub fn new(url: &str) -> Self {
        Database {
            url: url.into()
        }
    }

    pub fn create(self) -> Self {
        let (database, postgres_url) = self.split_url();
        let conn = PgConnection::establish(&postgres_url).unwrap();
        conn.execute(&format!("CREATE DATABASE {}", database)).unwrap();
        self
    }

    pub fn exists(&self) -> bool {
        PgConnection::establish(&self.url).is_ok()
    }

    pub fn table_exists(&self, table: &str) -> bool {
        select(sql::<Bool>(&format!("EXISTS \
                (SELECT 1 \
                 FROM information_schema.tables \
                 WHERE table_name = '{}')", table)))
            .get_result(&self.conn()).unwrap()
    }

    pub fn conn(&self) -> PgConnection {
        PgConnection::establish(&self.url)
            .expect(&format!("Failed to open connection to {}", &self.url))
    }

    pub fn execute(&self, command: &str) {
        self.conn().execute(command)
            .expect(&format!("Error executing command {}", command));
    }

    fn split_url(&self) -> (String, String) {
        let mut split: Vec<&str> = self.url.split("/").collect();
        let database = split.pop().unwrap();
        let postgres_url = split.join("/");
        (database.into(), postgres_url)
    }
}

impl Drop for Database {
    fn drop(&mut self) {
        let (database, postgres_url) = self.split_url();
        let conn = PgConnection::establish(&postgres_url).unwrap();
        conn.silence_notices(|| {
            conn.execute(&format!("DROP DATABASE IF EXISTS {}", database)).unwrap();
        });
    }
}
<commit_msg>Properly drop databases in CLI's tests<commit_after>use diesel::expression::sql;
use diesel::pg::PgConnection;
use diesel::types::Bool;
use diesel::{Connection, select, LoadDsl};

pub struct Database {
    url: String
}

impl Database {
    pub fn new(url: &str) -> Self {
        Database {
            url: url.into()
        }
    }

    pub fn create(self) -> Self {
        let (database, postgres_url) = self.split_url();
        let conn = PgConnection::establish(&postgres_url).unwrap();
        conn.execute(&format!("CREATE DATABASE {}", database)).unwrap();
        self
    }

    pub fn exists(&self) -> bool {
        PgConnection::establish(&self.url).is_ok()
    }

    pub fn table_exists(&self, table: &str) -> bool {
        select(sql::<Bool>(&format!("EXISTS \
                (SELECT 1 \
                 FROM information_schema.tables \
                 WHERE table_name = '{}')", table)))
            .get_result(&self.conn()).unwrap()
    }

    pub fn conn(&self) -> PgConnection {
        PgConnection::establish(&self.url)
            .expect(&format!("Failed to open connection to {}", &self.url))
    }

    pub fn execute(&self, command: &str) {
        self.conn().execute(command)
            .expect(&format!("Error executing command {}", command));
    }

    fn split_url(&self) -> (String, String) {
        let mut split: Vec<&str> = self.url.split("/").collect();
        let database = split.pop().unwrap();
        let postgres_url = format!("{}/{}", split.join("/"), "postgres");
        (database.into(), postgres_url)
    }
}

impl Drop for Database {
    fn drop(&mut self) {
        let (database, postgres_url) = self.split_url();
        let conn = PgConnection::establish(&postgres_url).unwrap();
        conn.silence_notices(|| {
            conn.execute(&format!("DROP DATABASE IF EXISTS {}", database)).unwrap();
        });
    }
}
<|endoftext|>