<commit_before>use ::memory::VAddr;
use alloc::PAGE_SIZE;

pub mod paddr_impls;
pub use self::paddr_impls::*;

pub mod table;
pub use self::table::{Table, PML4, Entry};
use self::table::{HUGE_PAGE};

/// A physical (linear) memory address is a 64-bit unsigned integer
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct PAddr(u64);

impl PAddr {
    #[inline] pub const fn from_u64(u: u64) -> Self {
        PAddr(u)
    }
    #[inline] pub const fn as_u64(&self) -> u64 {
        self.0
    }
}

trait Translate {
    type To;
    fn translate(&self) -> Option<Self::To>;
}

impl Translate for VAddr {
    type To = PAddr;

    fn translate(&self) -> Option<PAddr> {
        Page::containing_addr(*self)
            .translate()
            .map(|frame| {
                let offset = self.as_usize() % PAGE_SIZE;
                PAddr::from_u64(frame as u64 + offset as u64)
            })
    }
}

impl Translate for Page {
    type To = *mut u8;

    fn translate(&self) -> Option<*mut u8> {
        let pdpt = unsafe { &*table::PML4 }.next_table(self.pml4_index());

        let huge_page = || pdpt.and_then(|pdpt| {
            let pdpt_entry = &pdpt[self.pdpt_index()];

            if pdpt_entry.flags().contains(HUGE_PAGE) {
                // If the PDPT entry contains the huge page flag, and the
                // entry points to the start frame of a page, then the pointed
                // frame is a 1GB huge page
                pdpt_entry.pointed_frame()
                    .map(|start_frame| {
                        assert!( start_frame as usize % table::N_ENTRIES == 0
                               , "Start frame must be aligned on a \
                                  1GB boundary!");
                        (start_frame as usize + self.pd_index()
                                              + self.pt_index()) as *mut u8
                    })

            } else {
                pdpt.next_table(self.pdpt_index())
                    .and_then(|pd| {
                        let pd_entry = &pd[self.pd_index()];

                        if pd_entry.flags().contains(HUGE_PAGE) {
                            pd_entry.pointed_frame()
                                .map(|start_frame|{
                                    assert!( (start_frame as usize %
                                             table::N_ENTRIES) == 0
                                         , "Start frame must be aligned!");
                                    (start_frame as usize + self.pt_index())
                                        as *mut u8
                                })
                        } else {
                            None
                        }
                    })
            }
        });

        pdpt.and_then(|pdpt| pdpt.next_table(self.pdpt_index()))
            .and_then(|pd| pd.next_table(self.pd_index()))
            .and_then(|pt| pt[self.pt_index()].pointed_frame())
            .or_else(huge_page)

    }
}

macro_rules! table_idx {
    ( $($name:ident >> $shift:expr)* ) => {$(
        pub fn $name(&self) -> usize {
            (self.number >> $shift) & 0o777
        }
    )*};
}

#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Page { pub number: usize }

impl Page {
    /// Create a new `Page` containing the given virtual address
    pub fn containing_addr(addr: VAddr) -> Page {
        assert!( addr.as_usize() < 0x0000_8000_0000_0000 ||
                 addr.as_usize() >= 0xffff_8000_0000_0000
               , "invalid address: 0x{:x}", addr );
        Page { number: (addr / PAGE_SIZE).as_usize() }
    }

    /// Return the start virtual address of this page
    pub fn start_addr(&self) -> VAddr {
        VAddr::from_usize(self.number * PAGE_SIZE)
    }

    table_idx!{
        pml4_index >> 27
        pdpt_index >> 18
        pd_index >> 9
        pt_index >> 0
    }

}
<commit_msg>[x86_64] Add page mapping functions for x86_64 active PML4<commit_after>use core::ptr::Unique;

use ::memory::VAddr;
use alloc::{PAGE_SIZE, Allocator};

pub mod paddr_impls;
pub use self::paddr_impls::*;

pub mod table;
use self::table::*;

/// A physical (linear) memory address is a 64-bit unsigned integer
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct PAddr(u64);

impl PAddr {
    #[inline] pub const fn from_u64(u: u64) -> Self {
        PAddr(u)
    }
    #[inline] pub const fn as_u64(&self) -> u64 {
        self.0
    }
}

macro_rules! table_idx {
    ( $($name:ident >> $shift:expr)* ) => {$(
        pub fn $name(&self) -> usize {
            (self.number >> $shift) & 0o777
        }
    )*};
}

#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Page { pub number: usize }

impl Page {
    /// Create a new `Page` containing the given virtual address
    pub fn containing_addr(addr: VAddr) -> Page {
        assert!( addr.as_usize() < 0x0000_8000_0000_0000 ||
                 addr.as_usize() >= 0xffff_8000_0000_0000
               , "invalid address: 0x{:x}", addr );
        Page { number: (addr / PAGE_SIZE).as_usize() }
    }

    /// Return the start virtual address of this page
    pub fn start_addr(&self) -> VAddr {
        VAddr::from_usize(self.number * PAGE_SIZE)
    }

    table_idx!{
        pml4_index >> 27
        pdpt_index >> 18
        pd_index >> 9
        pt_index >> 0
    }

}

pub struct ActivePML4(Unique<Table<PML4Level>>);

impl ActivePML4 {

    pub unsafe fn new() -> Self {
        ActivePML4(Unique::new(PML4))
    }

    fn pml4(&self) -> &Table<PML4Level> {
        unsafe { self.0.get() }
    }

    fn pml4_mut(&mut self) -> &mut Table<PML4Level> {
        unsafe { self.0.get_mut() }
    }

    fn translate(&self, vaddr: VAddr) -> Option<PAddr> {
        self.translate_page(Page::containing_addr(vaddr))
            .map(|frame| {
                let offset = vaddr.as_usize() % PAGE_SIZE;
                PAddr::from_u64(frame as u64 + offset as u64)
            })
    }

    pub fn translate_page(&self, page: Page) -> Option<*mut u8> {
        let pdpt = self.pml4().next_table(page.pml4_index());

        let huge_page = || pdpt.and_then(|pdpt| {
            let pdpt_entry = &pdpt[page.pdpt_index()];

            if pdpt_entry.flags().contains(HUGE_PAGE) {
                // If the PDPT entry contains the huge page flag, and the
                // entry points to the start frame of a page, then the pointed
                // frame is a 1GB huge page
                pdpt_entry.pointed_frame()
                    .map(|start_frame| {
                        assert!( start_frame as usize % table::N_ENTRIES == 0
                               , "Start frame must be aligned on a \
                                  1GB boundary!");
                        (start_frame as usize + page.pd_index()
                                              + page.pt_index()) as *mut u8
                    })

            } else {
                pdpt.next_table(page.pdpt_index())
                    .and_then(|pd| {
                        let pd_entry = &pd[page.pd_index()];

                        if pd_entry.flags().contains(HUGE_PAGE) {
                            pd_entry.pointed_frame()
                                .map(|start_frame|{
                                    assert!( (start_frame as usize %
                                             table::N_ENTRIES) == 0
                                         , "Start frame must be aligned!");
                                    (start_frame as usize + page.pt_index())
                                        as *mut u8
                                })
                        } else {
                            None
                        }
                    })
            }
        });

        pdpt.and_then(|pdpt| pdpt.next_table(page.pdpt_index()))
            .and_then(|pd| pd.next_table(page.pd_index()))
            .and_then(|pt| pt[page.pt_index()].pointed_frame())
            .or_else(huge_page)

    }

    pub fn identity_map<A: Allocator>( &mut self
                                     , frame: *mut u8
                                     , flags: EntryFlags
                                     , allocator: &mut A) {
        self.map_to( Page::containing_addr(VAddr::from_ptr(frame))
                   , frame
                   , flags
                   , allocator )
    }

    pub fn map<A: Allocator>( &mut self
                            , page: Page
                            , flags: EntryFlags
                            , allocator: &mut A) {
        unsafe {
            self.map_to( page
                       , allocator.allocate(PAGE_SIZE, PAGE_SIZE)
                                  .expect("Couldn't map, out of frames!")
                       , flags
                       , allocator );
        }
    }

    pub fn map_to<A: Allocator>( &mut self
                               , page: Page
                               , frame: *mut u8
                               , flags: EntryFlags
                               , allocator: &mut A) {
        let mut pdpt = self.pml4_mut()
                           .create_next(page.pml4_index(), allocator);
        let mut pd   = pdpt.create_next(page.pdpt_index(), allocator);
        let mut pt   = pd.create_next(page.pd_index(), allocator);

        let idx = page.pt_index();

        assert!(pt[idx].is_unused()
               , "Could not map frame {:?}, page table entry {} is already \
                  in use!", frame, idx);
        pt[idx].set(frame, flags | PRESENT);
    }

}
<|endoftext|>


<commit_before>extern crate gcc;

use std::process::Command;

fn main() {

    Command::new("git")
        .args(&["clone", "https://github.com/potassco/clingo.git"])
        .status()
        .unwrap();

    Command::new("git")
        .args(&["checkout", "tags/v5.1.0"])
        .current_dir("./clingo")
        .status()
        .unwrap();

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/libgringo/src/control.cc")
        .file("clingo/libgringo/src/term.cc")
        .file("clingo/libgringo/src/symbol.cc")
        .file("clingo/libgringo/src/primes.cc")
        .file("clingo/libgringo/src/backend.cc")
        .file("clingo/libgringo/src/lua.cc")
        .file("clingo/libgringo/src/scripts.cc")
        .file("clingo/libgringo/src/python.cc")
        .file("clingo/libgringo/src/terms.cc")
        .file("clingo/libgringo/src/ground/statements.cc")
        .file("clingo/libgringo/src/ground/literals.cc")
        .file("clingo/libgringo/src/ground/instantiation.cc")
        .file("clingo/libgringo/src/input/groundtermparser.cc")
        .file("generated/input/nongroundgrammar/grammar.cc")
        .file("generated/input/groundtermgrammar/grammar.cc")
        .file("clingo/libgringo/src/input/nongroundparser.cc")
        .file("clingo/libgringo/src/input/aggregate.cc")
        .file("clingo/libgringo/src/input/aggregates.cc")
        .file("clingo/libgringo/src/input/program.cc")
        .file("clingo/libgringo/src/ground/program.cc")
        .file("clingo/libgringo/src/input/programbuilder.cc")
        .file("clingo/libgringo/src/input/literals.cc")
        .file("clingo/libgringo/src/input/statement.cc")
        .file("clingo/libgringo/src/input/literal.cc")
        .file("clingo/libgringo/src/input/theory.cc")
        .file("clingo/libgringo/src/output/statements.cc")
        .file("clingo/libgringo/src/output/literals.cc")
        .file("clingo/libgringo/src/output/aggregates.cc")
        .file("clingo/libgringo/src/output/output.cc")
        .file("clingo/libgringo/src/output/statement.cc")
        .file("clingo/libgringo/src/output/literal.cc")
        .file("clingo/libgringo/src/output/theory.cc")
        .include("clingo/libgringo")
        .include("generated")
        .include("clingo/liblp")
        .include("clingo/libreify")
        .compile("libgringo.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/libprogram_opts/src/application.cpp")
        .file("clingo/libprogram_opts/src/alarm.cpp")
        .file("clingo/libprogram_opts/src/program_options.cpp")
        .file("clingo/libprogram_opts/src/string_convert.cpp")
        .file("clingo/libprogram_opts/src/value_store.cpp")
        .include("clingo/libprogram_opts")
        .compile("libprogram_opts.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/libreify/src/program.cc")
        .include("clingo/libreify")
        .include("clingo/liblp")
        .include("clingo/libgringo")
        .compile("libreify.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/liblp/src/aspif.cpp")
        .file("clingo/liblp/src/clingo.cpp")
        .file("clingo/liblp/src/theory_data.cpp")
        .file("clingo/liblp/src/smodels.cpp")
        .file("clingo/liblp/src/convert.cpp")
        .file("clingo/liblp/src/rule_utils.cpp")
        .file("clingo/liblp/src/match_basic_types.cpp")
        .file("clingo/liblp/src/aspif_text.cpp")
        .include("clingo/liblp")
        .compile("liblp.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .define("WITH_THREADS", Some("0"))
        .file("clingo/libclingo/src/clingocontrol.cc")
        .include("clingo/libclingo")
        .include("clingo/libgringo")
        .include("clingo/liblp")
        .include("clingo/libclasp")
        .include("clingo/libprogram_opts")
        .compile("libclingo.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .define("WITH_THREADS", Some("0"))
        .file("clingo/libclasp/src/parallel_solve.cpp")
        .file("clingo/libclasp/src/solver_types.cpp")
        .file("clingo/libclasp/src/solver_strategies.cpp")
        .file("clingo/libclasp/src/clause.cpp")
        .file("clingo/libclasp/src/logic_program.cpp")
        .file("clingo/libclasp/src/clasp_facade.cpp")
        .file("clingo/libclasp/src/cb_enumerator.cpp")
        .file("clingo/libclasp/src/minimize_constraint.cpp")
        .file("clingo/libclasp/src/clingo.cpp")
        .file("clingo/libclasp/src/shared_context.cpp")
        .file("clingo/libclasp/src/dependency_graph.cpp")
        .file("clingo/libclasp/src/logic_program_types.cpp")
        .file("clingo/libclasp/src/asp_preprocessor.cpp")
        .file("clingo/libclasp/src/clasp_options.cpp")
        .file("clingo/libclasp/src/heuristics.cpp")
        .file("clingo/libclasp/src/timer.cpp")
        .file("clingo/libclasp/src/lookahead.cpp")
        .file("clingo/libclasp/src/constraint.cpp")
        .file("clingo/libclasp/src/unfounded_check.cpp")
        .file("clingo/libclasp/src/solver.cpp")
        .file("clingo/libclasp/src/model_enumerators.cpp")
        .file("clingo/libclasp/src/clasp_output.cpp")
        .file("clingo/libclasp/src/parser.cpp")
        .file("clingo/libclasp/src/solve_algorithms.cpp")
        .file("clingo/libclasp/src/enumerator.cpp")
        .file("clingo/libclasp/src/program_builder.cpp")
        .file("clingo/libclasp/src/satelite.cpp")
        .file("clingo/libclasp/src/statistics.cpp")
        .file("clingo/libclasp/src/weight_constraint.cpp")
        .include("clingo/libclasp")
        .include("clingo/libclingo")
        .include("clingo/liblp")
        .include("clingo/libprogram_opts")
        .compile("libclasp.a");

    println!("cargo:rustc-link-lib=static=clingo");
    println!("cargo:rustc-link-lib=static=clasp");
    println!("cargo:rustc-link-lib=static=program_opts");
    println!("cargo:rustc-link-lib=static=lp");
    println!("cargo:rustc-link-lib=static=reify");
    println!("cargo:rustc-link-lib=static=gringo");

//     println!("cargo:rustc-link-lib=python3.6m");
//     -DWITH_PYTHON=1 -I/usr/include/python3.6m

}
<commit_msg>check if the clingo directory already exists<commit_after>extern crate gcc;

use std::path::Path;
use std::process::Command;

fn main() {
    if ! Path::new("clingo").exists() {
        Command::new("git")
            .args(&["clone", "https://github.com/potassco/clingo.git"])
            .status()
            .unwrap();
    }
    Command::new("git")
        .args(&["checkout", "tags/v5.1.0"])
        .current_dir("./clingo")
        .status()
        .unwrap();

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/libgringo/src/control.cc")
        .file("clingo/libgringo/src/term.cc")
        .file("clingo/libgringo/src/symbol.cc")
        .file("clingo/libgringo/src/primes.cc")
        .file("clingo/libgringo/src/backend.cc")
        .file("clingo/libgringo/src/lua.cc")
        .file("clingo/libgringo/src/scripts.cc")
        .file("clingo/libgringo/src/python.cc")
        .file("clingo/libgringo/src/terms.cc")
        .file("clingo/libgringo/src/ground/statements.cc")
        .file("clingo/libgringo/src/ground/literals.cc")
        .file("clingo/libgringo/src/ground/instantiation.cc")
        .file("clingo/libgringo/src/input/groundtermparser.cc")
        .file("generated/input/nongroundgrammar/grammar.cc")
        .file("generated/input/groundtermgrammar/grammar.cc")
        .file("clingo/libgringo/src/input/nongroundparser.cc")
        .file("clingo/libgringo/src/input/aggregate.cc")
        .file("clingo/libgringo/src/input/aggregates.cc")
        .file("clingo/libgringo/src/input/program.cc")
        .file("clingo/libgringo/src/ground/program.cc")
        .file("clingo/libgringo/src/input/programbuilder.cc")
        .file("clingo/libgringo/src/input/literals.cc")
        .file("clingo/libgringo/src/input/statement.cc")
        .file("clingo/libgringo/src/input/literal.cc")
        .file("clingo/libgringo/src/input/theory.cc")
        .file("clingo/libgringo/src/output/statements.cc")
        .file("clingo/libgringo/src/output/literals.cc")
        .file("clingo/libgringo/src/output/aggregates.cc")
        .file("clingo/libgringo/src/output/output.cc")
        .file("clingo/libgringo/src/output/statement.cc")
        .file("clingo/libgringo/src/output/literal.cc")
        .file("clingo/libgringo/src/output/theory.cc")
        .include("clingo/libgringo")
        .include("generated")
        .include("clingo/liblp")
        .include("clingo/libreify")
        .compile("libgringo.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/libprogram_opts/src/application.cpp")
        .file("clingo/libprogram_opts/src/alarm.cpp")
        .file("clingo/libprogram_opts/src/program_options.cpp")
        .file("clingo/libprogram_opts/src/string_convert.cpp")
        .file("clingo/libprogram_opts/src/value_store.cpp")
        .include("clingo/libprogram_opts")
        .compile("libprogram_opts.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/libreify/src/program.cc")
        .include("clingo/libreify")
        .include("clingo/liblp")
        .include("clingo/libgringo")
        .compile("libreify.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .file("clingo/liblp/src/aspif.cpp")
        .file("clingo/liblp/src/clingo.cpp")
        .file("clingo/liblp/src/theory_data.cpp")
        .file("clingo/liblp/src/smodels.cpp")
        .file("clingo/liblp/src/convert.cpp")
        .file("clingo/liblp/src/rule_utils.cpp")
        .file("clingo/liblp/src/match_basic_types.cpp")
        .file("clingo/liblp/src/aspif_text.cpp")
        .include("clingo/liblp")
        .compile("liblp.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .define("WITH_THREADS", Some("0"))
        .file("clingo/libclingo/src/clingocontrol.cc")
        .include("clingo/libclingo")
        .include("clingo/libgringo")
        .include("clingo/liblp")
        .include("clingo/libclasp")
        .include("clingo/libprogram_opts")
        .compile("libclingo.a");

    gcc::Config::new()
        .cpp(true)
        .define("NDEBUG", Some("1"))
        .define("WITH_THREADS", Some("0"))
        .file("clingo/libclasp/src/parallel_solve.cpp")
        .file("clingo/libclasp/src/solver_types.cpp")
        .file("clingo/libclasp/src/solver_strategies.cpp")
        .file("clingo/libclasp/src/clause.cpp")
        .file("clingo/libclasp/src/logic_program.cpp")
        .file("clingo/libclasp/src/clasp_facade.cpp")
        .file("clingo/libclasp/src/cb_enumerator.cpp")
        .file("clingo/libclasp/src/minimize_constraint.cpp")
        .file("clingo/libclasp/src/clingo.cpp")
        .file("clingo/libclasp/src/shared_context.cpp")
        .file("clingo/libclasp/src/dependency_graph.cpp")
        .file("clingo/libclasp/src/logic_program_types.cpp")
        .file("clingo/libclasp/src/asp_preprocessor.cpp")
        .file("clingo/libclasp/src/clasp_options.cpp")
        .file("clingo/libclasp/src/heuristics.cpp")
        .file("clingo/libclasp/src/timer.cpp")
        .file("clingo/libclasp/src/lookahead.cpp")
        .file("clingo/libclasp/src/constraint.cpp")
        .file("clingo/libclasp/src/unfounded_check.cpp")
        .file("clingo/libclasp/src/solver.cpp")
        .file("clingo/libclasp/src/model_enumerators.cpp")
        .file("clingo/libclasp/src/clasp_output.cpp")
        .file("clingo/libclasp/src/parser.cpp")
        .file("clingo/libclasp/src/solve_algorithms.cpp")
        .file("clingo/libclasp/src/enumerator.cpp")
        .file("clingo/libclasp/src/program_builder.cpp")
        .file("clingo/libclasp/src/satelite.cpp")
        .file("clingo/libclasp/src/statistics.cpp")
        .file("clingo/libclasp/src/weight_constraint.cpp")
        .include("clingo/libclasp")
        .include("clingo/libclingo")
        .include("clingo/liblp")
        .include("clingo/libprogram_opts")
        .compile("libclasp.a");

    println!("cargo:rustc-link-lib=static=clingo");
    println!("cargo:rustc-link-lib=static=clasp");
    println!("cargo:rustc-link-lib=static=program_opts");
    println!("cargo:rustc-link-lib=static=lp");
    println!("cargo:rustc-link-lib=static=reify");
    println!("cargo:rustc-link-lib=static=gringo");

//     println!("cargo:rustc-link-lib=python3.6m");
//     -DWITH_PYTHON=1 -I/usr/include/python3.6m

}
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(collections_drain)]
#![feature(slice_patterns)]
#![feature(alloc)]

extern crate rustc_serialize;
extern crate websocket;
extern crate time;

macro_rules! time {
    ($name:expr, $expr:expr) => {{
        let start = ::time::precise_time_s();
        let result = $expr;
        let end = ::time::precise_time_s();
        println!("{} took {}s", $name, end - start);
        result
    }};
}

macro_rules! string {
    ($($args:expr),*) => (::value::Value::String(format!($($args),*)))
}

pub mod value;
// pub mod map;
pub mod relation;
pub mod view;
pub mod flow;
pub mod primitive;
pub mod compiler;
pub mod server;
// pub mod test;
<commit_msg>Fixed unused feature warning<commit_after>#![feature(collections)]
#![feature(slice_patterns)]

extern crate rustc_serialize;
extern crate websocket;
extern crate time;

macro_rules! time {
    ($name:expr, $expr:expr) => {{
        let start = ::time::precise_time_s();
        let result = $expr;
        let end = ::time::precise_time_s();
        println!("{} took {}s", $name, end - start);
        result
    }};
}

macro_rules! string {
    ($($args:expr),*) => (::value::Value::String(format!($($args),*)))
}

pub mod value;
// pub mod map;
pub mod relation;
pub mod view;
pub mod flow;
pub mod primitive;
pub mod compiler;
pub mod server;
// pub mod test;
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(slice_patterns)]
extern crate rustc_serialize;
extern crate cbor;
extern crate websocket;
extern crate time;
extern crate hyper;
extern crate cookie;
extern crate url;
extern crate mime;

macro_rules! time {
    ($name:expr, $expr:expr) => {{
        let start = ::time::precise_time_s();
        let result = $expr;
        let end = ::time::precise_time_s();
        println!("{} took {}s", $name, end - start);
        result
    }};
}

macro_rules! string {
    ($($args:expr),*) => (::value::Value::String(format!($($args),*)))
}

pub mod value;
pub mod map;
pub mod relation;
pub mod view;
pub mod flow;
pub mod primitive;
pub mod compiler;
pub mod server;
pub mod client;
// pub mod test;
<commit_msg>Also forgot to add alloc feature<commit_after>#![feature(collections)]
#![feature(slice_patterns)]
#![feature(alloc)]
extern crate rustc_serialize;
extern crate cbor;
extern crate websocket;
extern crate time;
extern crate hyper;
extern crate cookie;
extern crate url;
extern crate mime;

macro_rules! time {
    ($name:expr, $expr:expr) => {{
        let start = ::time::precise_time_s();
        let result = $expr;
        let end = ::time::precise_time_s();
        println!("{} took {}s", $name, end - start);
        result
    }};
}

macro_rules! string {
    ($($args:expr),*) => (::value::Value::String(format!($($args),*)))
}

pub mod value;
pub mod map;
pub mod relation;
pub mod view;
pub mod flow;
pub mod primitive;
pub mod compiler;
pub mod server;
pub mod client;
// pub mod test;
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::env;

mod api;

use crate::api::database::Database;
use crate::api::mailman::{Api, ListRole};

fn main() {
    env_logger::init();
    let database = env::var("DATABASE").expect("Database env var not present");

    let db = Database::new("localhost", 27017, &database);

    let api = Api::new(
        "http://10.135.57.30:8001/3.0",
        "restadmin",
        "CKtB8n86O4SocRv2T23r0IL5oxndClOzcDGZovDx5sP3rJUC",
    );

    let additional_accepted_non_members: HashSet<String> = vec![
        String::from("besetning@nidarholm.no"),
        String::from("okonomi@nidarholm.no"),
        String::from("info@nidarholm.no"),
        String::from("leder@nidarholm.no"),
        String::from("leder.turogfest@nidarholm.no"),
    ]
    .into_iter()
    .collect();

    let mut user_map = HashMap::new();
    let mut role_map = HashMap::new();
    let mut role_users_map = HashMap::new();

    let organization = db.get_organization("nidarholm");
    let member_group_id = &organization.member_group_id;

    let group = db.get_group_by_id(member_group_id);

    for member in group.members {
        let user = db.get_user_by_id(&member.user_id);
        let is_member = user.is_member(member_group_id);
        let in_lists = user.in_lists(is_member);
        if in_lists {
            user_map.insert(member.user_id.clone(), user);
        }

        for role_id in member.role_ids {
            let role = db.get_role_by_id(&role_id);
            role_map.insert(role_id.clone(), role.to_owned());
            if !role_users_map.contains_key(&role_id) {
                role_users_map.insert(role_id.clone(), Vec::new());
            }
            role_users_map
                .get_mut(&role_id)
                .expect("Key not found, while it was already checked to be there")
                .push(member.user_id.clone());
        }
    }

    // Set of all members
    let all_members: HashSet<String> = user_map.values().map(|user| user.email.clone()).collect();

    // Find moderators to use for all lists
    let moderator_group = db.get_group_by_name("Listemoderatorer");

    let mut moderator_emails: HashSet<String> = HashSet::new();
    for mod_member in moderator_group.members {
        let moderator_user = user_map.get(&mod_member.user_id).unwrap_or_else(|| {
            panic!(
                "Could not get moderator from user map {}",
                mod_member.user_id
            )
        });
        let moderator_email = &moderator_user.email;
        if !moderator_email.is_empty() {
            moderator_emails.insert(moderator_email.clone());
        }
    }
    // TODO: Do not override when things have stabilized
    let mut moderator_emails: HashSet<String> = HashSet::new();
    moderator_emails.insert(String::from("sigurdga@sigurdga.no"));

    // VERV-ADRESSER
    for (role_id, user_ids) in &role_users_map {
        let role = role_map
            .get(role_id)
            .expect("Could not get role from role_map");
        let role_email = &role.email;
        if role_email.is_empty() {
            continue;
        }

        let mut emails: HashSet<String> = HashSet::new();

        for user_id in user_ids {
            let user = user_map
                .get(user_id)
                .unwrap_or_else(|| panic!("Could not get user from user map {}", user_id));
            if !role_email.is_empty() && !user.email.is_empty() {
                emails.insert(user.email.to_owned());
            }
        }
        api.update_members(role_email, emails, ListRole::Member);
        api.update_members(role_email, moderator_emails.clone(), ListRole::Moderator);
        api.update_members(
            role_email,
            additional_accepted_non_members.clone(),
            ListRole::NonMember,
        );
    }

    // Used for special group "gruppeledere"
    let mut all_group_leaders: HashSet<String> = HashSet::new();

    let concert_master_role = db.get_role_by_name("Konsertmester");
    match role_users_map.get(&concert_master_role.id) {
        None => {}
        Some(concert_masters) => {
            for user_id in concert_masters {
                if let Some(user) = user_map.get(user_id) {
                    if !user.email.is_empty() {
                        all_group_leaders.insert(user.email.to_owned());
                    }
                }
            }
        }
    }

    for group in db.get_all_groups() {
        let mut group_members: HashSet<String> = HashSet::new();
        let mut group_leaders: HashSet<String> = HashSet::new();
        for member in group.members {
            let user_id = member.user_id;
            if let Some(user) = user_map.get(&user_id) {
                if !user.email.is_empty() {
                    group_members.insert(user.email.to_owned());

                    let group_leader_email = &group.group_leader_email;
                    if !group_leader_email.is_empty() {
                        let role_ids = member.role_ids;
                        if !role_ids.is_empty() {
                            group_leaders.insert(user.email.to_owned());
                            all_group_leaders.insert(user.email.to_owned());
                        }
                    }
                }
            }
        }

        if !group.email.is_empty() {
            let group_leader_email = group.group_leader_email;
            if group_leader_email.is_empty() {
                // Gruppe uten gruppeledere
                api.update_members(&group.email, group_members.clone(), ListRole::Member);
                api.update_members(&group.email, moderator_emails.clone(), ListRole::Moderator);
            } else {
                // Gruppe med gruppeledere
                api.update_members(&group_leader_email, group_leaders.clone(), ListRole::Member);
                api.update_members(&group.email, group_members.clone(), ListRole::Member);
                api.update_members(
                    &group_leader_email,
                    moderator_emails.clone(),
                    ListRole::Moderator,
                );
                api.update_members(&group.email, moderator_emails.clone(), ListRole::Moderator);
                api.update_members(
                    &group_leader_email,
                    all_members.difference(&group_leaders).cloned().collect(),
                    ListRole::NonMember,
                );
            }
            api.update_members(
                &group.email,
                all_members.difference(&group_members).cloned().collect(),
                ListRole::NonMember,
            );
            api.update_members(
                &group.email,
                additional_accepted_non_members.to_owned(),
                ListRole::NonMember,
            );
        }
    }

    let all_group_leaders_email = "gruppeledere@nidarholm.no";

    api.update_members(
        all_group_leaders_email,
        all_group_leaders.clone(),
        ListRole::Member,
    );
    api.update_members(
        all_group_leaders_email,
        moderator_emails,
        ListRole::Moderator,
    );
    api.update_members(
        all_group_leaders_email,
        all_members
            .difference(&all_group_leaders)
            .cloned()
            .collect(),
        ListRole::NonMember,
    );
    api.update_members(
        all_group_leaders_email,
        additional_accepted_non_members,
        ListRole::NonMember,
    );
}
<commit_msg>log user map<commit_after>use std::collections::{HashMap, HashSet};
use std::env;

mod api;

use crate::api::database::Database;
use crate::api::mailman::{Api, ListRole};

fn main() {
    env_logger::init();
    let database = env::var("DATABASE").expect("Database env var not present");

    let db = Database::new("localhost", 27017, &database);

    let api = Api::new(
        "http://10.135.57.30:8001/3.0",
        "restadmin",
        "CKtB8n86O4SocRv2T23r0IL5oxndClOzcDGZovDx5sP3rJUC",
    );

    let additional_accepted_non_members: HashSet<String> = vec![
        String::from("besetning@nidarholm.no"),
        String::from("okonomi@nidarholm.no"),
        String::from("info@nidarholm.no"),
        String::from("leder@nidarholm.no"),
        String::from("leder.turogfest@nidarholm.no"),
    ]
    .into_iter()
    .collect();

    let mut user_map = HashMap::new();
    let mut role_map = HashMap::new();
    let mut role_users_map = HashMap::new();

    let organization = db.get_organization("nidarholm");
    let member_group_id = &organization.member_group_id;

    let group = db.get_group_by_id(member_group_id);

    for member in group.members {
        let user = db.get_user_by_id(&member.user_id);
        let is_member = user.is_member(member_group_id);
        let in_lists = user.in_lists(is_member);
        if in_lists {
            user_map.insert(member.user_id.clone(), user);
        }

        for role_id in member.role_ids {
            let role = db.get_role_by_id(&role_id);
            role_map.insert(role_id.clone(), role.to_owned());
            if !role_users_map.contains_key(&role_id) {
                role_users_map.insert(role_id.clone(), Vec::new());
            }
            role_users_map
                .get_mut(&role_id)
                .expect("Key not found, while it was already checked to be there")
                .push(member.user_id.clone());
        }
    }

    // Set of all members
    let all_members: HashSet<String> = user_map
        .iter()
        .map(|(id, user)| {
            println!("{} {}", id, user.email);
            user.email.clone()
        })
        .collect();

    // Find moderators to use for all lists
    let moderator_group = db.get_group_by_name("Listemoderatorer");

    let mut moderator_emails: HashSet<String> = HashSet::new();
    for mod_member in moderator_group.members {
        let moderator_user = user_map.get(&mod_member.user_id).unwrap_or_else(|| {
            panic!(
                "Could not get moderator from user map {}",
                mod_member.user_id
            )
        });
        let moderator_email = &moderator_user.email;
        if !moderator_email.is_empty() {
            moderator_emails.insert(moderator_email.clone());
        }
    }
    // TODO: Do not override when things have stabilized
    let mut moderator_emails: HashSet<String> = HashSet::new();
    moderator_emails.insert(String::from("sigurdga@sigurdga.no"));

    // VERV-ADRESSER
    for (role_id, user_ids) in &role_users_map {
        let role = role_map
            .get(role_id)
            .expect("Could not get role from role_map");
        let role_email = &role.email;
        if role_email.is_empty() {
            continue;
        }

        let mut emails: HashSet<String> = HashSet::new();

        for user_id in user_ids {
            let user = user_map
                .get(user_id)
                .unwrap_or_else(|| panic!("Could not get user from user map {}", user_id));
            if !role_email.is_empty() && !user.email.is_empty() {
                emails.insert(user.email.to_owned());
            }
        }
        api.update_members(role_email, emails, ListRole::Member);
        api.update_members(role_email, moderator_emails.clone(), ListRole::Moderator);
        api.update_members(
            role_email,
            additional_accepted_non_members.clone(),
            ListRole::NonMember,
        );
    }

    // Used for special group "gruppeledere"
    let mut all_group_leaders: HashSet<String> = HashSet::new();

    let concert_master_role = db.get_role_by_name("Konsertmester");
    match role_users_map.get(&concert_master_role.id) {
        None => {}
        Some(concert_masters) => {
            for user_id in concert_masters {
                if let Some(user) = user_map.get(user_id) {
                    if !user.email.is_empty() {
                        all_group_leaders.insert(user.email.to_owned());
                    }
                }
            }
        }
    }

    for group in db.get_all_groups() {
        let mut group_members: HashSet<String> = HashSet::new();
        let mut group_leaders: HashSet<String> = HashSet::new();
        for member in group.members {
            let user_id = member.user_id;
            if let Some(user) = user_map.get(&user_id) {
                if !user.email.is_empty() {
                    group_members.insert(user.email.to_owned());

                    let group_leader_email = &group.group_leader_email;
                    if !group_leader_email.is_empty() {
                        let role_ids = member.role_ids;
                        if !role_ids.is_empty() {
                            group_leaders.insert(user.email.to_owned());
                            all_group_leaders.insert(user.email.to_owned());
                        }
                    }
                }
            }
        }

        if !group.email.is_empty() {
            let group_leader_email = group.group_leader_email;
            if group_leader_email.is_empty() {
                // Gruppe uten gruppeledere
                api.update_members(&group.email, group_members.clone(), ListRole::Member);
                api.update_members(&group.email, moderator_emails.clone(), ListRole::Moderator);
            } else {
                // Gruppe med gruppeledere
                api.update_members(&group_leader_email, group_leaders.clone(), ListRole::Member);
                api.update_members(&group.email, group_members.clone(), ListRole::Member);
                api.update_members(
                    &group_leader_email,
                    moderator_emails.clone(),
                    ListRole::Moderator,
                );
                api.update_members(&group.email, moderator_emails.clone(), ListRole::Moderator);
                api.update_members(
                    &group_leader_email,
                    all_members.difference(&group_leaders).cloned().collect(),
                    ListRole::NonMember,
                );
            }
            api.update_members(
                &group.email,
                all_members.difference(&group_members).cloned().collect(),
                ListRole::NonMember,
            );
            api.update_members(
                &group.email,
                additional_accepted_non_members.to_owned(),
                ListRole::NonMember,
            );
        }
    }

    let all_group_leaders_email = "gruppeledere@nidarholm.no";

    api.update_members(
        all_group_leaders_email,
        all_group_leaders.clone(),
        ListRole::Member,
    );
    api.update_members(
        all_group_leaders_email,
        moderator_emails,
        ListRole::Moderator,
    );
    api.update_members(
        all_group_leaders_email,
        all_members
            .difference(&all_group_leaders)
            .cloned()
            .collect(),
        ListRole::NonMember,
    );
    api.update_members(
        all_group_leaders_email,
        additional_accepted_non_members,
        ListRole::NonMember,
    );
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use library::*;
use nameutil;
use parser::is_empty_c_type;
use traits::MaybeRefAs;

impl Namespace {
    fn unresolved(&self) -> Vec<&str> {
        self.index
            .iter()
            .filter_map(|(name, &id)| if self.types[id as usize].is_none() {
                Some(&name[..])
            } else {
                None
            })
            .collect()
    }
}

type DetectedCTypes = HashMap<TypeId, String>;

impl Library {
    pub fn postprocessing(&mut self) {
        self.fix_gtype();
        self.check_resolved();
        self.fill_empty_signals_c_types();
        self.resolve_class_structs();
        self.correlate_class_structs();
        self.fix_fields();
    }

    fn fix_gtype(&mut self) {
        if let Some(ns_id) = self.find_namespace("GObject") {
            // hide the `GType` type alias in `GObject`
            self.add_type(ns_id, "Type", Type::Fundamental(Fundamental::Unsupported));
        }
    }

    fn check_resolved(&self) {
        let list: Vec<_> = self.index
            .iter()
            .flat_map(|(name, &id)| {
                let name = name.clone();
                self.namespace(id)
                    .unresolved()
                    .into_iter()
                    .map(move |s| format!("{}.{}", name, s))
            })
            .collect();

        if !list.is_empty() {
            panic!("Incomplete library, unresolved: {:?}", list);
        }
    }

    fn fill_empty_signals_c_types(&mut self) {
        let mut tids = Vec::new();
        let mut c_types = DetectedCTypes::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(ref klass) => {
                        if self.detect_empty_signals_c_types(&klass.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    Type::Interface(ref iface) => {
                        if self.detect_empty_signals_c_types(&iface.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    _ => (),
                }
            }
        }

        fn update_empty_signals_c_types(signals: &mut [Signal], c_types: &DetectedCTypes) {
            for signal in signals {
                update_empty_signal_c_types(signal, c_types);
            }
        }

        fn update_empty_signal_c_types(signal: &mut Signal, c_types: &DetectedCTypes) {
            for par in &mut signal.parameters {
                update_empty_c_type(&mut par.c_type, par.typ, c_types);
            }
            update_empty_c_type(&mut signal.ret.c_type, signal.ret.typ, c_types);
        }

        fn update_empty_c_type(c_type: &mut String, tid: TypeId, c_types: &DetectedCTypes) {
            if !is_empty_c_type(c_type) {
                return;
            }
            if let Some(ref mut s) = c_types.get(&tid) {
                *c_type = s.clone();
            }
        }

        for tid in tids {
            match *self.type_mut(tid) {
                Type::Class(ref mut klass) => {
                    update_empty_signals_c_types(&mut klass.signals, &c_types)
                }
                Type::Interface(ref mut iface) => {
                    update_empty_signals_c_types(&mut iface.signals, &c_types)
                }
                _ => (),
            }
        }
    }

    fn detect_empty_signals_c_types(
        &self,
        signals: &[Signal],
        c_types: &mut DetectedCTypes,
    ) -> bool {
        let mut detected = false;
        for signal in signals {
            if self.detect_empty_signal_c_types(signal, c_types) {
                detected = true;
            }
        }
        detected
    }

    fn detect_empty_signal_c_types(&self, signal: &Signal, c_types: &mut DetectedCTypes) -> bool {
        let mut detected = false;
        for par in &signal.parameters {
            if self.detect_empty_c_type(&par.c_type, par.typ, c_types) {
                detected = true;
            }
        }
        if self.detect_empty_c_type(&signal.ret.c_type, signal.ret.typ, c_types) {
            detected = true;
        }
        detected
    }

    fn detect_empty_c_type(&self, c_type: &str, tid: TypeId, c_types: &mut DetectedCTypes) -> bool {
        if !is_empty_c_type(c_type) {
            return false;
        }
        if !c_types.contains_key(&tid) {
            if let Some(detected_c_type) = self.c_type_by_type_id(tid) {
                c_types.insert(tid, detected_c_type);
            }
        }
        true
    }

    fn c_type_by_type_id(&self, tid: TypeId) -> Option<String> {
        let type_ = self.type_(tid);
        type_
            .get_glib_name()
            .map(|glib_name| if self.is_referenced_type(type_) {
                format!("{}*", glib_name)
            } else {
                glib_name.to_string()
            })
    }

    fn is_referenced_type(&self, type_: &Type) -> bool {
        use library::Type::*;
        match *type_ {
            Alias(ref alias) => self.is_referenced_type(self.type_(alias.typ)),
            Record(..) | Union(..) | Class(..) | Interface(..) => true,
            _ => false,
        }
    }

    fn resolve_class_structs(&mut self) {
        // stores pairs of (gtype-struct-c-name, type-name)
        let mut structs_and_types = Vec::new();

        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in &ns.types {
                let type_ = type_.as_ref().unwrap(); //Always contains something

                if let Type::Record(ref record) = *type_ {
                    if let Some(ref struct_for) = record.gtype_struct_for {
                        if let Some(struct_for_tid) = self.find_type(ns_id as u16, struct_for) {
                            structs_and_types.push ((record.c_type.clone(), struct_for_tid));
                        }
                    }
                }
            }
        }

        for (gtype_struct_c_type, struct_for_tid) in structs_and_types {
            match *self.type_mut(struct_for_tid) {
                Type::Class(ref mut klass) => {
                    klass.c_class_type = Some(gtype_struct_c_type);
                },

                Type::Interface(ref mut iface) => {
                    iface.c_class_type = Some(gtype_struct_c_type);
                },

                ref x => unreachable!("Something other than a class or interface has a class struct: {:?}", x)
            }
        }
    }

    fn correlate_class_structs(&self) {
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in &ns.types {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let name;
                let type_struct;
                let c_class_type;

                match *type_ {
                    Type::Class(ref klass) => {
                        name         = &klass.name;
                        type_struct  = &klass.type_struct;
                        c_class_type = &klass.c_class_type;
                    },

                    Type::Interface(ref iface) => {
                        name         = &iface.name;
                        type_struct  = &iface.type_struct;
                        c_class_type = &iface.c_class_type;
                    },

                    _ => { continue; }
                }

                if let Some(ref type_struct) = *type_struct {
                    let type_struct_tid = self.find_type(ns_id as u16, type_struct);
                    if type_struct_tid.is_none() {
                        panic!("\"{}\" has glib:type-struct=\"{}\" but there is no such record",
                               name,
                               type_struct);
                    }

                    let type_struct_type = self.type_(type_struct_tid.unwrap());

                    if let Type::Record(ref r) = *type_struct_type {
                        if r.gtype_struct_for.as_ref() != Some(name) {
                            if let Some(ref gtype_struct_for) = r.gtype_struct_for {
                                panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has glib:is-gtype-struct-for={:?}",
                                       name,
                                       type_struct,
                                       r.name,
                                       gtype_struct_for);
                            } else {
                                panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has no glib:is-gtype-struct-for attribute",
                                       name,
                                       type_struct,
                                       r.name);
                            }
                        }
                    } else {
                        panic!("Element with name=\"{}\" should be a record but it isn't",
                               type_struct);
                    }
                } else if let Some(ref c) = *c_class_type {
                    panic!("\"{}\" has no glib:type-struct but there is an element with glib:is-gtype-struct-for=\"{}\"",
                           name,
                           c);
                }
                // else both type_struct and c_class_type are None,
                // and that's fine because they don't reference each
                // other.
            }
        }
    }

    fn fix_fields(&mut self) {
        enum Action {
            SetCType(String),
            SetName(String),
        }
        let mut actions: Vec<(TypeId, usize, Action)> = Vec::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(Class { ref name, ref fields, ..}) |
                    Type::Record(Record { ref name, ref fields, ..}) |
                    Type::Union(Union { ref name, ref fields, ..}) => {
                        for (fid, field) in fields.iter().enumerate() {
                            if nameutil::needs_mangling(&field.name) {
                                let new_name = nameutil::mangle_keywords(&*field.name).to_string();
                                actions.push((tid, fid, Action::SetName(new_name)));
                            }
                            if field.c_type.is_some() {
                                continue;
                            }
                            let field_type = self.type_(field.typ);
                            if let Some(_) = field_type.maybe_ref_as::<Function>() {
                                // Function pointers generally don't have c_type.
                                continue;
                            }
                            if let Some(c_type) = field_type.get_glib_name() {
                                actions.push((tid, fid, Action::SetCType(c_type.to_owned())));
                                continue;
                            }
                            if let Type::Fundamental(Fundamental::Pointer) = *field_type {
                                // For example SoupBuffer is missing c:type for data field.
                                actions.push((tid, fid, Action::SetCType("void*".to_owned())));
                                continue;
                            }
                            error!("Field `{}::{}` is missing c:type", name, &field.name);
                        }
                    },
                    _ => {},
                }
            }
        }
        for (tid, fid, action) in actions {
            match *self.type_mut(tid) {
                Type::Class(Class { ref name, ref mut fields, ..}) |
                Type::Record(Record { ref name, ref mut fields, ..}) |
                Type::Union(Union { ref name, ref mut fields, ..}) => {
                    match action {
                        Action::SetCType(c_type) => {
                            warn!("Field `{}::{}` missing c:type assumed to be `{}`",
                                  name, &fields[fid].name, c_type);
                            fields[fid].c_type = Some(c_type);
                        }
                        Action::SetName(name) => fields[fid].name = name,
                    }
                },
                _ => unreachable!("Expected class, record or union"),
            }
        }
    }
}
<commit_msg>Make unrepresentable types (class, struct, union) opaque.<commit_after>use std::collections::HashMap;

use library::*;
use nameutil;
use parser::is_empty_c_type;
use traits::MaybeRefAs;

impl Namespace {
    fn unresolved(&self) -> Vec<&str> {
        self.index
            .iter()
            .filter_map(|(name, &id)| if self.types[id as usize].is_none() {
                Some(&name[..])
            } else {
                None
            })
            .collect()
    }
}

type DetectedCTypes = HashMap<TypeId, String>;

impl Library {
    pub fn postprocessing(&mut self) {
        self.fix_gtype();
        self.check_resolved();
        self.fill_empty_signals_c_types();
        self.resolve_class_structs();
        self.correlate_class_structs();
        self.fix_fields();
        self.make_unrepresentable_types_opaque();
    }

    fn fix_gtype(&mut self) {
        if let Some(ns_id) = self.find_namespace("GObject") {
            // hide the `GType` type alias in `GObject`
            self.add_type(ns_id, "Type", Type::Fundamental(Fundamental::Unsupported));
        }
    }

    fn check_resolved(&self) {
        let list: Vec<_> = self.index
            .iter()
            .flat_map(|(name, &id)| {
                let name = name.clone();
                self.namespace(id)
                    .unresolved()
                    .into_iter()
                    .map(move |s| format!("{}.{}", name, s))
            })
            .collect();

        if !list.is_empty() {
            panic!("Incomplete library, unresolved: {:?}", list);
        }
    }

    fn fill_empty_signals_c_types(&mut self) {
        let mut tids = Vec::new();
        let mut c_types = DetectedCTypes::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(ref klass) => {
                        if self.detect_empty_signals_c_types(&klass.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    Type::Interface(ref iface) => {
                        if self.detect_empty_signals_c_types(&iface.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    _ => (),
                }
            }
        }

        fn update_empty_signals_c_types(signals: &mut [Signal], c_types: &DetectedCTypes) {
            for signal in signals {
                update_empty_signal_c_types(signal, c_types);
            }
        }

        fn update_empty_signal_c_types(signal: &mut Signal, c_types: &DetectedCTypes) {
            for par in &mut signal.parameters {
                update_empty_c_type(&mut par.c_type, par.typ, c_types);
            }
            update_empty_c_type(&mut signal.ret.c_type, signal.ret.typ, c_types);
        }

        fn update_empty_c_type(c_type: &mut String, tid: TypeId, c_types: &DetectedCTypes) {
            if !is_empty_c_type(c_type) {
                return;
            }
            if let Some(ref mut s) = c_types.get(&tid) {
                *c_type = s.clone();
            }
        }

        for tid in tids {
            match *self.type_mut(tid) {
                Type::Class(ref mut klass) => {
                    update_empty_signals_c_types(&mut klass.signals, &c_types)
                }
                Type::Interface(ref mut iface) => {
                    update_empty_signals_c_types(&mut iface.signals, &c_types)
                }
                _ => (),
            }
        }
    }

    fn detect_empty_signals_c_types(
        &self,
        signals: &[Signal],
        c_types: &mut DetectedCTypes,
    ) -> bool {
        let mut detected = false;
        for signal in signals {
            if self.detect_empty_signal_c_types(signal, c_types) {
                detected = true;
            }
        }
        detected
    }

    fn detect_empty_signal_c_types(&self, signal: &Signal, c_types: &mut DetectedCTypes) -> bool {
        let mut detected = false;
        for par in &signal.parameters {
            if self.detect_empty_c_type(&par.c_type, par.typ, c_types) {
                detected = true;
            }
        }
        if self.detect_empty_c_type(&signal.ret.c_type, signal.ret.typ, c_types) {
            detected = true;
        }
        detected
    }

    fn detect_empty_c_type(&self, c_type: &str, tid: TypeId, c_types: &mut DetectedCTypes) -> bool {
        if !is_empty_c_type(c_type) {
            return false;
        }
        if !c_types.contains_key(&tid) {
            if let Some(detected_c_type) = self.c_type_by_type_id(tid) {
                c_types.insert(tid, detected_c_type);
            }
        }
        true
    }

    fn c_type_by_type_id(&self, tid: TypeId) -> Option<String> {
        let type_ = self.type_(tid);
        type_
            .get_glib_name()
            .map(|glib_name| if self.is_referenced_type(type_) {
                format!("{}*", glib_name)
            } else {
                glib_name.to_string()
            })
    }

    fn is_referenced_type(&self, type_: &Type) -> bool {
        use library::Type::*;
        match *type_ {
            Alias(ref alias) => self.is_referenced_type(self.type_(alias.typ)),
            Record(..) | Union(..) | Class(..) | Interface(..) => true,
            _ => false,
        }
    }

    fn resolve_class_structs(&mut self) {
        // stores pairs of (gtype-struct-c-name, type-name)
        let mut structs_and_types = Vec::new();

        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in &ns.types {
                let type_ = type_.as_ref().unwrap(); //Always contains something

                if let Type::Record(ref record) = *type_ {
                    if let Some(ref struct_for) = record.gtype_struct_for {
                        if let Some(struct_for_tid) = self.find_type(ns_id as u16, struct_for) {
                            structs_and_types.push ((record.c_type.clone(), struct_for_tid));
                        }
                    }
                }
            }
        }

        for (gtype_struct_c_type, struct_for_tid) in structs_and_types {
            match *self.type_mut(struct_for_tid) {
                Type::Class(ref mut klass) => {
                    klass.c_class_type = Some(gtype_struct_c_type);
                },

                Type::Interface(ref mut iface) => {
                    iface.c_class_type = Some(gtype_struct_c_type);
                },

                ref x => unreachable!("Something other than a class or interface has a class struct: {:?}", x)
            }
        }
    }

    fn correlate_class_structs(&self) {
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in &ns.types {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let name;
                let type_struct;
                let c_class_type;

                match *type_ {
                    Type::Class(ref klass) => {
                        name         = &klass.name;
                        type_struct  = &klass.type_struct;
                        c_class_type = &klass.c_class_type;
                    },

                    Type::Interface(ref iface) => {
                        name         = &iface.name;
                        type_struct  = &iface.type_struct;
                        c_class_type = &iface.c_class_type;
                    },

                    _ => { continue; }
                }

                if let Some(ref type_struct) = *type_struct {
                    let type_struct_tid = self.find_type(ns_id as u16, type_struct);
                    if type_struct_tid.is_none() {
                        panic!("\"{}\" has glib:type-struct=\"{}\" but there is no such record",
                               name,
                               type_struct);
                    }

                    let type_struct_type = self.type_(type_struct_tid.unwrap());

                    if let Type::Record(ref r) = *type_struct_type {
                        if r.gtype_struct_for.as_ref() != Some(name) {
                            if let Some(ref gtype_struct_for) = r.gtype_struct_for {
                                panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has glib:is-gtype-struct-for={:?}",
                                       name,
                                       type_struct,
                                       r.name,
                                       gtype_struct_for);
                            } else {
                                panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has no glib:is-gtype-struct-for attribute",
                                       name,
                                       type_struct,
                                       r.name);
                            }
                        }
                    } else {
                        panic!("Element with name=\"{}\" should be a record but it isn't",
                               type_struct);
                    }
                } else if let Some(ref c) = *c_class_type {
                    panic!("\"{}\" has no glib:type-struct but there is an element with glib:is-gtype-struct-for=\"{}\"",
                           name,
                           c);
                }
                // else both type_struct and c_class_type are None,
                // and that's fine because they don't reference each
                // other.
            }
        }
    }

    fn fix_fields(&mut self) {
        enum Action {
            SetCType(String),
            SetName(String),
        }
        let mut actions: Vec<(TypeId, usize, Action)> = Vec::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(Class { ref name, ref fields, ..}) |
                    Type::Record(Record { ref name, ref fields, ..}) |
                    Type::Union(Union { ref name, ref fields, ..}) => {
                        for (fid, field) in fields.iter().enumerate() {
                            if nameutil::needs_mangling(&field.name) {
                                let new_name = nameutil::mangle_keywords(&*field.name).to_string();
                                actions.push((tid, fid, Action::SetName(new_name)));
                            }
                            if field.c_type.is_some() {
                                continue;
                            }
                            let field_type = self.type_(field.typ);
                            if let Some(_) = field_type.maybe_ref_as::<Function>() {
                                // Function pointers generally don't have c_type.
                                continue;
                            }
                            if let Some(c_type) = field_type.get_glib_name() {
                                actions.push((tid, fid, Action::SetCType(c_type.to_owned())));
                                continue;
                            }
                            if let Type::Fundamental(Fundamental::Pointer) = *field_type {
                                // For example SoupBuffer is missing c:type for data field.
                                actions.push((tid, fid, Action::SetCType("void*".to_owned())));
                                continue;
                            }
                            error!("Field `{}::{}` is missing c:type", name, &field.name);
                        }
                    },
                    _ => {},
                }
            }
        }
        for (tid, fid, action) in actions {
            match *self.type_mut(tid) {
                Type::Class(Class { ref name, ref mut fields, ..}) |
                Type::Record(Record { ref name, ref mut fields, ..}) |
                Type::Union(Union { ref name, ref mut fields, ..}) => {
                    match action {
                        Action::SetCType(c_type) => {
                            warn!("Field `{}::{}` missing c:type assumed to be `{}`",
                                  name, &fields[fid].name, c_type);
                            fields[fid].c_type = Some(c_type);
                        }
                        Action::SetName(name) => fields[fid].name = name,
                    }
                },
                _ => unreachable!("Expected class, record or union"),
            }
        }
    }

    fn make_unrepresentable_types_opaque(&mut self) {
        let mut unrepresentable: Vec<(TypeId, String)> = Vec::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap();
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(Class {ref fields, ..}) |
                    Type::Record(Record {ref fields, ..}) |
                    Type::Union(Union {ref fields, ..}) if !fields.is_empty() => {
                        if let Err(reason) = is_representable(self, tid) {
                            unrepresentable.push((tid, reason));
                        }
                    },
                    _ => {},
                }
            }
        }
        for (tid, reason) in unrepresentable {
            match *self.type_mut(tid) {
                Type::Class(Class {ref name, ref mut fields, ..}) |
                Type::Record(Record {ref name, ref mut fields, ..}) |
                Type::Union(Union {ref name, ref mut fields, ..}) => {
                    info!("Type `{}` is not representable: {}.", name, reason);
                    fields.clear();
                }
                _ => unreachable!("Expected class, record or union"),
            }
        }
    }
}

fn is_representable(lib: &Library, tid: TypeId) -> Result<(), String> {
    match *lib.type_(tid) {
        Type::Fundamental(Fundamental::None) => Err("void".to_owned()),
        Type::Fundamental(Fundamental::Unsupported) => Err("unsupported".to_owned()),
        Type::Fundamental(_) => Ok(()),
        Type::Alias(ref alias) => {
            if is_ptr(lib, &alias.target_c_type) {
                return Ok(())
            }
            is_representable(lib, alias.typ)
        },
        Type::Class(Class {ref fields, ..}) |
        Type::Record(Record {ref fields, ..}) => {
            if fields.is_empty() {
                return Err("opaque type".to_owned())
            }
            for field in fields {
                if field.bits.is_some() {
                    return Err(format!("{} is bitfield", field.name));
                }
                if let Some(ref c_type) = field.c_type {
                    if !is_ptr(lib, c_type) {
                        if let Err(reason) = is_representable(lib, field.typ) {
                            return Err(format!("{}::{}", field.name, reason));
                        }
                    }
                }
            }
            Ok(())
        },
        Type::Union(..) => Err("union".to_owned()),
        Type::Interface(..) => Err("interface".to_owned()),
        Type::FixedArray(inner, ..) => {
            is_representable(lib, inner)
        },
        Type::Function(..) |
        Type::Enumeration(..) |
        Type::Bitfield(..) |
        Type::Array(..) |
        Type::CArray(..) |
        Type::PtrArray(..) |
        Type::HashTable(..) |
        Type::List(..) |
        Type::SList(..) => {
            Ok(())
        }
    }
}

fn is_ptr(_lib: &Library, c_type: &str) -> bool {
    c_type.contains("*")
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use rustc_data_structures::fx::FxHashMap;

use crate::externalfiles::ExternalHtml;
use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};

#[derive(Clone)]
crate struct Layout {
    crate logo: String,
    crate favicon: String,
    crate external_html: ExternalHtml,
    crate default_settings: FxHashMap<String, String>,
    crate krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    crate css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    crate generate_search_filter: bool,
}

crate struct Page<'a> {
    crate title: &'a str,
    crate css_class: &'a str,
    crate root_path: &'a str,
    crate static_root_path: Option<&'a str>,
    crate description: &'a str,
    crate keywords: &'a str,
    crate resource_suffix: &'a str,
    crate extra_scripts: &'a [&'a str],
    crate static_extra_scripts: &'a [&'a str],
}

impl<'a> Page<'a> {
    crate fn get_static_root_path(&self) -> &str {
        self.static_root_path.unwrap_or(self.root_path)
    }
}

crate fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    style_files: &[StylePath],
) -> String {
    let static_root_path = page.get_static_root_path();
    format!(
        "<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {style_files}\
    \
    \
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\" title=\"themes\">\
            \
        </button>\

\

\
    \
        <form class=\"search-form\">\

\

{filter_crates}\
                    <input class=\"search-input\" name=\"search\" \
                           disabled \
                           autocomplete=\"off\" \
                           spellcheck=\"false\" \
                           placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                           type=\"search\">\

\
                <button type=\"button\" id=\"help-button\" title=\"help\">?</button>
                \
                    \
                \

\
        </form>\
    \

{content}
\

\
    {after_content}\

\
    \
    {extra_scripts}\
\
",
        css_extension = if layout.css_file_extension.is_some() {
            format!(
                "<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            String::new()
        },
        content = Buffer::html().to_display(t),
        static_root_path = static_root_path,
        root_path = page.root_path,
        css_class = page.css_class,
        logo = {
            if layout.logo.is_empty() {
                format!(
                    "\

\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    static_root_path = static_root_path,
                    suffix = page.resource_suffix
                )
            } else {
                format!(
                    "\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    logo = layout.logo
                )
            }
        },
        title = page.title,
        description = Escape(page.description),
        keywords = page.keywords,
        favicon = if layout.favicon.is_empty() {
            format!(
                r##"<link rel="icon" type="image/svg+xml" href="{static_root_path}favicon{suffix}.svg">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-16x16{suffix}.png">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-32x32{suffix}.png">"##,
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
        },
        in_header = layout.external_html.in_header,
        before_content = layout.external_html.before_content,
        after_content = layout.external_html.after_content,
        sidebar = Buffer::html().to_display(sidebar),
        krate = layout.krate,
        default_settings = layout
            .default_settings
            .iter()
            .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v)))
            .collect::<String>(),
        style_files = style_files
            .iter()
            .filter_map(|t| {
                if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
            })
            .filter_map(|t| {
                if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None }
            })
            .map(|t| format!(
                r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
                Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
                if t.1 { "disabled" } else { "" },
                if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
            ))
            .collect::<String>(),
        suffix = page.resource_suffix,
        extra_scripts = page
            .static_extra_scripts
            .iter()
            .map(|e| {
                format!(
                    "",
                    static_root_path = static_root_path,
                    extra_script = e
                )
            })
            .chain(page.extra_scripts.iter().map(|e| {
                format!(
                    "",
                    root_path = page.root_path,
                    extra_script = e
                )
            }))
            .collect::<String>(),
        filter_crates = if layout.generate_search_filter {
            "<select id=\"crate-search\">\
                 <option value=\"All crates\">All crates</option>\
             </select>"
        } else {
            ""
        },
    )
}

crate fn redirect(url: &str) -> String {
    //

"##,
        url = url,
    )
}
<commit_msg>Add missing backslash in HTML layout string<commit_after>use std::path::PathBuf;

use rustc_data_structures::fx::FxHashMap;

use crate::externalfiles::ExternalHtml;
use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};

#[derive(Clone)]
crate struct Layout {
    crate logo: String,
    crate favicon: String,
    crate external_html: ExternalHtml,
    crate default_settings: FxHashMap<String, String>,
    crate krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    crate css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    crate generate_search_filter: bool,
}

crate struct Page<'a> {
    crate title: &'a str,
    crate css_class: &'a str,
    crate root_path: &'a str,
    crate static_root_path: Option<&'a str>,
    crate description: &'a str,
    crate keywords: &'a str,
    crate resource_suffix: &'a str,
    crate extra_scripts: &'a [&'a str],
    crate static_extra_scripts: &'a [&'a str],
}

impl<'a> Page<'a> {
    crate fn get_static_root_path(&self) -> &str {
        self.static_root_path.unwrap_or(self.root_path)
    }
}

crate fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    style_files: &[StylePath],
) -> String {
    let static_root_path = page.get_static_root_path();
    format!(
        "<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {style_files}\
    \
    \
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\" title=\"themes\">\
            \
        </button>\

\

\
    \
        <form class=\"search-form\">\

\

{filter_crates}\
                    <input class=\"search-input\" name=\"search\" \
                           disabled \
                           autocomplete=\"off\" \
                           spellcheck=\"false\" \
                           placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                           type=\"search\">\

\
                <button type=\"button\" id=\"help-button\" title=\"help\">?</button>\
                \
                    \
                \

\
        </form>\
    \

{content}
\

\
    {after_content}\

\
    \
    {extra_scripts}\
\
",
        css_extension = if layout.css_file_extension.is_some() {
            format!(
                "<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            String::new()
        },
        content = Buffer::html().to_display(t),
        static_root_path = static_root_path,
        root_path = page.root_path,
        css_class = page.css_class,
        logo = {
            if layout.logo.is_empty() {
                format!(
                    "\

\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    static_root_path = static_root_path,
                    suffix = page.resource_suffix
                )
            } else {
                format!(
                    "\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    logo = layout.logo
                )
            }
        },
        title = page.title,
        description = Escape(page.description),
        keywords = page.keywords,
        favicon = if layout.favicon.is_empty() {
            format!(
                r##"<link rel="icon" type="image/svg+xml" href="{static_root_path}favicon{suffix}.svg">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-16x16{suffix}.png">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-32x32{suffix}.png">"##,
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
        },
        in_header = layout.external_html.in_header,
        before_content = layout.external_html.before_content,
        after_content = layout.external_html.after_content,
        sidebar = Buffer::html().to_display(sidebar),
        krate = layout.krate,
        default_settings = layout
            .default_settings
            .iter()
            .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v)))
            .collect::<String>(),
        style_files = style_files
            .iter()
            .filter_map(|t| {
                if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
            })
            .filter_map(|t| {
                if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None }
            })
            .map(|t| format!(
                r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
                Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
                if t.1 { "disabled" } else { "" },
                if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
            ))
            .collect::<String>(),
        suffix = page.resource_suffix,
        extra_scripts = page
            .static_extra_scripts
            .iter()
            .map(|e| {
                format!(
                    "",
                    static_root_path = static_root_path,
                    extra_script = e
                )
            })
            .chain(page.extra_scripts.iter().map(|e| {
                format!(
                    "",
                    root_path = page.root_path,
                    extra_script = e
                )
            }))
            .collect::<String>(),
        filter_crates = if layout.generate_search_filter {
            "<select id=\"crate-search\">\
                 <option value=\"All crates\">All crates</option>\
             </select>"
        } else {
            ""
        },
    )
}

crate fn redirect(url: &str) -> String {
    //

"##,
        url = url,
    )
}
<|endoftext|>


<commit_before>enum State {
    Whitespace,
    IntegralPart,
    FractionalPart,
    ExponentSign,
    Exponent
}

pub fn strtod (string: &str) -> (f64, &str) {
    let mut state = State::Whitespace;
    let mut value: f64 = 0.0;
    let mut sign: f64 = 1.0;
    let mut fraction: f64 = 1.0;
    let mut exponent_sign: f64 = 1.0;
    let mut exponent: f64 = 0.0;
    let mut last_pos: usize = 0;

    for (pos, c) in string.chars ().enumerate () {
        last_pos = pos;

        match state {
            State::Whitespace => {
                if c.is_whitespace () {
                    continue;
                } else if c == '+' || c == '-' {
                    if c == '-' {
                        sign = -1.0;
                    }

                    state = State::IntegralPart;
                } else if c.is_digit (10) {
                    state = State::IntegralPart;
                    value = (c as i32 - '0' as i32) as f64;
                } else if c == '.' {
                    state = State::FractionalPart;
                } else {
                    break;
                }
            },

            State::IntegralPart => {
                if c.is_digit (10) {
                    value = value * 10.0 + (c as i32 - '0' as i32) as f64;
                } else if c == '.' {
                    state = State::FractionalPart;
                } else if c == 'e' || c == 'E' {
                    state = State::ExponentSign;
                } else {
                    break;
                }
            },

            State::FractionalPart => {
                if c.is_digit (10) {
                    fraction *= 0.1;
                    value += fraction * (c as i32 - '0' as i32) as f64;
                } else if c == 'e' || c == 'E' {
                    state = State::ExponentSign;
                } else {
                    break;
                }
            },

            State::ExponentSign => {
                if c == '+' || c == '-' {
                    if c == '-' {
                        exponent_sign = -1.0;
                    }

                    state = State::Exponent;
                } else if c.is_digit (10) {
                    exponent = (c as i32 - '0' as i32) as f64;
                } else {
                    break;
                }
            },

            State::Exponent => {
                if c.is_digit (10) {
                    exponent = exponent * 10.0 + (c as i32 - '0' as i32) as f64;
                } else {
                    break;
                }
            }
        }

        last_pos += 1;
    }

    // return tuple with the value and the non-matching slice

    (sign * value * 10.0f64.powf (exponent * exponent_sign),
     &string[last_pos .. ])
}

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

    #[test]
    fn handles_empty_string () {
        let str = "";
        assert_eq! (strtod (str), (0.0f64, &str[0..]));
    }

    #[test]
    fn handles_integer () {
        let str = "-123foo";
        assert_eq! (strtod (str), (-123.0f64, &str[4..]));

        let str = "12345";
        assert_eq! (strtod (str), (12345.0f64, &str[5..]));
    }

    #[test]
    fn handles_float () {
        let str = "-123.25";
        assert_eq! (strtod (str), (-123.25f64, &str[7..]));

        let str = "123.25bar";
        assert_eq! (strtod (str), (123.25f64, &str[6..]));
    }

    #[test]
    fn handles_dot_numbers () {
        let str = "-.25foo";
        assert_eq! (strtod (str), (-0.25f64, &str[4..]));

        let str = ".25";
        assert_eq! (strtod (str), (0.25f64, &str[3..]));
    }

    #[test]
    fn handles_dot () {
        let str = "-.";
        assert_eq! (strtod (str), (-0.0, &str[2..]));

        let str = ".bar";
        assert_eq! (strtod (str), (0.0, &str[1..]));
    }

    #[test]
    fn handles_exponent () {
        let str = "-123.45e2foo";
        assert_eq! (strtod (str), (-12345.0, &str[9..]));

        let str = "123.45E2";
        assert_eq! (strtod (str), (12345.0, &str[8..]));
    }

    #[test]
    fn handles_negative_exponent () {
        let str = "-123.25e-2";
        assert_eq! (strtod (str), (-1.2325, &str[10..]));

        let str = "123.25E-2bar";
        assert_eq! (strtod (str), (1.2325, &str[9..]));
    }
}
<commit_msg>strtod.rs: Don't consume the 'e' in strtod("42em")<commit_after>enum State {
    Whitespace,
    IntegralPart,
    FractionalPart,
    ExponentSign,
    Exponent
}

pub fn strtod (string: &str) -> (f64, &str) {
    let mut state = State::Whitespace;
    let mut value: f64 = 0.0;
    let mut sign: f64 = 1.0;
    let mut fraction: f64 = 1.0;
    let mut exponent_sign: f64 = 1.0;
    let mut exponent: f64 = 0.0;
    let mut last_pos: usize = 0;

    for (pos, c) in string.chars ().enumerate () {
        last_pos = pos;

        match state {
            State::Whitespace => {
                if c.is_whitespace () {
                    continue;
                } else if c == '+' || c == '-' {
                    if c == '-' {
                        sign = -1.0;
                    }

                    state = State::IntegralPart;
                } else if c.is_digit (10) {
                    state = State::IntegralPart;
                    value = (c as i32 - '0' as i32) as f64;
                } else if c == '.' {
                    state = State::FractionalPart;
                } else {
                    break;
                }
            },

            State::IntegralPart => {
                if c.is_digit (10) {
                    value = value * 10.0 + (c as i32 - '0' as i32) as f64;
                } else if c == '.' {
                    state = State::FractionalPart;
                } else if c == 'e' || c == 'E' {
                    state = State::ExponentSign;
                } else {
                    break;
                }
            },

            State::FractionalPart => {
                if c.is_digit (10) {
                    fraction *= 0.1;
                    value += fraction * (c as i32 - '0' as i32) as f64;
                } else if c == 'e' || c == 'E' {
                    state = State::ExponentSign;
                } else {
                    break;
                }
            },

            State::ExponentSign => {
                if c == '+' || c == '-' {
                    if c == '-' {
                        exponent_sign = -1.0;
                    }

                    state = State::Exponent;
                } else if c.is_digit (10) {
                    exponent = (c as i32 - '0' as i32) as f64;
                    state = State::Exponent;
                } else {
                    // un-consume the 'e' or 'E', so strtod("42em") produces the expected value.
                    last_pos -= 1;
                    break;
                }
            },

            State::Exponent => {
                if c.is_digit (10) {
                    exponent = exponent * 10.0 + (c as i32 - '0' as i32) as f64;
                } else {
                    break;
                }
            }
        }

        last_pos += 1;
    }

    // return tuple with the value and the non-matching slice

    (sign * value * 10.0f64.powf (exponent * exponent_sign),
     &string[last_pos .. ])
}

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

    #[test]
    fn handles_empty_string () {
        let str = "";
        assert_eq! (strtod (str), (0.0f64, &str[0..]));
    }

    #[test]
    fn handles_integer () {
        let str = "-123foo";
        assert_eq! (strtod (str), (-123.0f64, &str[4..]));

        let str = "12345";
        assert_eq! (strtod (str), (12345.0f64, &str[5..]));
    }

    #[test]
    fn handles_float () {
        let str = "-123.25";
        assert_eq! (strtod (str), (-123.25f64, &str[7..]));

        let str = "123.25bar";
        assert_eq! (strtod (str), (123.25f64, &str[6..]));
    }

    #[test]
    fn handles_dot_numbers () {
        let str = "-.25foo";
        assert_eq! (strtod (str), (-0.25f64, &str[4..]));

        let str = ".25bar";
        assert_eq! (strtod (str), (0.25f64, &str[3..]));

        let str = "22.5em";
        assert_eq! (strtod (str), (22.5, "em"));

        let str = "22.5e1Ex";
        assert_eq! (strtod (str), (225.0, "Ex"));

        let str = "22.5Ex";
        assert_eq! (strtod (str), (22.5, "Ex"));
    }

    #[test]
    fn handles_dot () {
        let str = "-.";
        assert_eq! (strtod (str), (-0.0, &str[2..]));

        let str = ".bar";
        assert_eq! (strtod (str), (0.0, &str[1..]));
    }

    #[test]
    fn handles_exponent () {
        let str = "-123.45e2foo";
        assert_eq! (strtod (str), (-12345.0, &str[9..]));

        let str = "123.45E2";
        assert_eq! (strtod (str), (12345.0, &str[8..]));

        let str = "123.45E10";
        assert_eq! (strtod (str), (1234500000000.0, &str[9..]));
    }

    #[test]
    fn handles_negative_exponent () {
        let str = "-123.25e-2";
        assert_eq! (strtod (str), (-1.2325, &str[10..]));

        let str = "123.25E-2bar";
        assert_eq! (strtod (str), (1.2325, &str[9..]));
    }
}
<|endoftext|>