<commit_before>use token::Token;
use book::{Book, compile_str};
use number::Number;
use error::Result;
use templates::odt;
use zipper::Zipper;
use parser::Parser;

use crowbook_text_processing::escape;

/// Rendererer for ODT
///
/// Still very experimental.
pub struct OdtRenderer<'a> {
    book: &'a Book,
    current_numbering: i32,
    current_hide: bool,
    current_chapter: i32,
    automatic_styles: String,
}

impl<'a> OdtRenderer<'a> {
    /// Creates a new OdtRenderer
    pub fn new(book: &'a Book) -> OdtRenderer {
        OdtRenderer {
            book: book,
            current_chapter: 1,
            current_numbering: book.options.get_i32("rendering.num_depth").unwrap(),
            current_hide: false,
            automatic_styles: String::from("
<style:style style:name=\"T1\" \
                                            style:family=\"text\">
  <style:text-properties \
                                            fo:font-style=\"italic\" \
                                            style:font-style-asian=\"italic\" \
                                            style:font-style-complex=\"italic\"/>
</style:style>
\
                                            <style:style style:name=\"T2\" \
                                            style:family=\"text\">
  <style:text-properties \
                                            fo:font-weight=\"bold\" \
                                            style:font-weight-asian=\"bold\" \
                                            style:font-weight-complex=\"bold\"/>
</style:style>"),
        }
    }

    /// Renders a full book
    ///
    /// This will try to generate an ODT file according to self.book options.
    ///
    /// # Returns
    /// * `Ok(s)` where `s` contains the output of the `zip` command
    ///   used to create the ODT file.
    /// * An error if there was somel problem during either the rendering to
    ///   ODT format, or the generation of the ODT file itself.
    pub fn render_book(&mut self) -> Result<String> {
        let content = try!(self.render_content());

        let mut zipper =
            try!(Zipper::new(&self.book.options.get_path("crowbook.temp_dir").unwrap()));

        // Write template.odt there
        try!(zipper.write("template.odt", odt::ODT, false));
        // unzip it
        try!(zipper.unzip("template.odt"));
        // Complete it with content.xml
        try!(zipper.write("content.xml", &content.as_bytes(), false));
        // Zip and copy
        if let Ok(ref file) = self.book.options.get_path("output.odt") {
            zipper.generate_odt(self.book.options.get_str("crowbook.zip.command").unwrap(),
                                file)
        } else {
            panic!(lformat!("odt.render_book called while book.output_odt is not set"));
        }
    }

    /// Render content.xml
    fn render_content(&mut self) -> Result<String> {
        let mut content = String::new();

        for &(n, ref v) in &self.book.chapters {
            self.current_hide = false;
            match n {
                Number::Unnumbered => self.current_numbering = 0,
                Number::Default => {
                    self.current_numbering =
                        self.book.options.get_i32("rendering.num_depth").unwrap()
                }
                Number::Specified(n) => {
                    self.current_numbering = self.book.options.get_i32("numbering").unwrap();
                    self.current_chapter = n;
                }
                Number::Hidden => {
                    self.current_numbering = 0;
                    self.current_hide = true;
                }
                _ => panic!(lformat!("Parts are not supported yet")),
            }
            for token in v {
                content.push_str(&self.parse_token(token));
            }
        }

        let template = try!(compile_str(odt::CONTENT,
                                        &self.book.source,
                                        "could not compile template for content.xml"));
        let data = try!(self.book.get_metadata(|s| Ok(s.to_owned())))
            .insert_str("content", content)
            .insert_str("automatic_styles", &self.automatic_styles)
            .build();

        let mut res: Vec<u8> = vec![];
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => panic!(lformat!("generated content.xml was not utf-8 valid")),
            Ok(res) => Ok(res),
        }
    }

    /// Transform a vector of `Token`s to Odt format
    fn render_vec(&mut self, tokens: &[Token]) -> String {
        let mut res = String::new();

        for token in tokens {
            res.push_str(&self.parse_token(&token));
        }
        res
    }

    fn parse_token(&mut self, token: &Token) -> String {
        match *token {
            Token::Str(ref text) => escape::html(self.book.clean(text.as_str(), false)).into_owned(),
            Token::Paragraph(ref vec) => {
                format!("<text:p text:style-name=\"Text_20_body\">{}</text:p>\n",
                        self.render_vec(vec))
            }
            Token::Header(n, ref vec) => {
                if n == 1 && self.current_hide {
                    return String::new();
                }
                let s = if n == 1 && self.current_numbering >= 1 {
                    let chapter = self.current_chapter;
                    self.current_chapter += 1;
                    let res = self.book.get_chapter_header(chapter, self.render_vec(vec), |s| {
                        Ok(self.render_vec(&try!(Parser::new().parse_inline(s))))
                    });
                    res.unwrap()
                } else {
                    self.render_vec(vec)
                };
                format!("<text:h text:style-name=\"Heading_20_{}\">\n{}</text:h>\n",
                        n,
                        s)
            }
            Token::Emphasis(ref vec) => {
                format!("<text:span text:style-name=\"T1\">{}</text:span>",
                        self.render_vec(vec))
            }
            Token::Strong(ref vec) => {
                format!("<text:span text:style-name=\"T2\">{}</text:span>",
                        self.render_vec(vec))
            }
            Token::List(ref vec) => format!("<text:list>\n{}</text:list>\n", self.render_vec(vec)),
            Token::OrderedList(_, ref vec) => {
                self.book
                    .logger
                    .warning(lformat!("ODT: ordered list not currently implemented for this \
                                       format, fallbacking to unordered one"));
                format!("<text:list>\n{}</text:list>\n", self.render_vec(vec))
            }
            Token::Item(ref vec) => {
                format!("<text:list-item>\n<text:p>{}</text:p></text:list-item>",
                        self.book.clean(self.render_vec(vec), false))
            }
            Token::Link(ref url, _, ref vec) => {
                format!("<text:a xlink:type=\"simple\"  xlink:href=\"{}\">{}</text:a>",
                        url,
                        self.render_vec(vec))
            }
            Token::Code(ref vec) => {
                format!("<text:span text:style-name=\"Preformatted_20_Text\">{}</text:span>",
                        self.render_vec(vec))
            }
            Token::BlockQuote(ref vec) |
            Token::CodeBlock(_, ref vec) => {
                self.book
                    .logger
                    .warning(lformat!("ODT: blockquotes and codeblocks are not currently \
                                       implemented for ODT"));
                format!("<text:p text:style-name=\"Text_20_Body\">{}</text:p>\n",
                        self.book.clean(self.render_vec(vec), false))
            }
            Token::SoftBreak | Token::HardBreak => String::from(" "),
            Token::Rule => String::from("<text:p /><text:p>***</text:p><text:p />"),
            Token::Image(_, _, _) |
            Token::StandaloneImage(_, _, _) => {
                self.book
                    .logger
                    .warning(lformat!("ODT: images not currently implemented for this format"));
                String::from(" ")
            }
            Token::Table(_, _) |
            Token::TableHead(_) |
            Token::TableRow(_) |
            Token::TableCell(_) => {
                self.book
                    .logger
                    .warning(lformat!("ODT: tables are not currently implemented for this format"));
                String::from(" ")
            }
            Token::Footnote(_) => {
                self.book
                    .logger
                    .warning(lformat!("ODT: footnotes are not yet implemented in this format, \
                                       ignoring {:?}",
                                      token));
                String::new()
            }
            Token::Annotation(_, ref vec) => self.render_vec(vec),
            Token::__NonExhaustive => unreachable!(),
        }
    }
}
<commit_msg>Fix bug in odt rendering<commit_after>use token::Token;
use book::{Book, compile_str};
use number::Number;
use error::Result;
use templates::odt;
use zipper::Zipper;
use parser::Parser;

use crowbook_text_processing::escape;

/// Rendererer for ODT
///
/// Still very experimental.
pub struct OdtRenderer<'a> {
    book: &'a Book,
    current_numbering: i32,
    current_hide: bool,
    current_chapter: i32,
    automatic_styles: String,
}

impl<'a> OdtRenderer<'a> {
    /// Creates a new OdtRenderer
    pub fn new(book: &'a Book) -> OdtRenderer {
        OdtRenderer {
            book: book,
            current_chapter: 1,
            current_numbering: book.options.get_i32("rendering.num_depth").unwrap(),
            current_hide: false,
            automatic_styles: String::from("
<style:style style:name=\"T1\" \
                                            style:family=\"text\">
  <style:text-properties \
                                            fo:font-style=\"italic\" \
                                            style:font-style-asian=\"italic\" \
                                            style:font-style-complex=\"italic\"/>
</style:style>
\
                                            <style:style style:name=\"T2\" \
                                            style:family=\"text\">
  <style:text-properties \
                                            fo:font-weight=\"bold\" \
                                            style:font-weight-asian=\"bold\" \
                                            style:font-weight-complex=\"bold\"/>
</style:style>"),
        }
    }

    /// Renders a full book
    ///
    /// This will try to generate an ODT file according to self.book options.
    ///
    /// # Returns
    /// * `Ok(s)` where `s` contains the output of the `zip` command
    ///   used to create the ODT file.
    /// * An error if there was somel problem during either the rendering to
    ///   ODT format, or the generation of the ODT file itself.
    pub fn render_book(&mut self) -> Result<String> {
        let content = try!(self.render_content());

        let mut zipper =
            try!(Zipper::new(&self.book.options.get_path("crowbook.temp_dir").unwrap()));

        // Write template.odt there
        try!(zipper.write("template.odt", odt::ODT, false));
        // unzip it
        try!(zipper.unzip("template.odt"));
        // Complete it with content.xml
        try!(zipper.write("content.xml", &content.as_bytes(), false));
        // Zip and copy
        if let Ok(ref file) = self.book.options.get_path("output.odt") {
            zipper.generate_odt(self.book.options.get_str("crowbook.zip.command").unwrap(),
                                file)
        } else {
            panic!(lformat!("odt.render_book called while book.output_odt is not set"));
        }
    }

    /// Render content.xml
    fn render_content(&mut self) -> Result<String> {
        let mut content = String::new();

        for &(n, ref v) in &self.book.chapters {
            self.current_hide = false;
            match n {
                Number::Unnumbered => self.current_numbering = 0,
                Number::Default => {
                    self.current_numbering =
                        self.book.options.get_i32("rendering.num_depth").unwrap()
                }
                Number::Specified(n) => {
                    self.current_numbering = self.book.options.get_i32("numbering").unwrap();
                    self.current_chapter = n;
                }
                Number::Hidden => {
                    self.current_numbering = 0;
                    self.current_hide = true;
                }
                _ => panic!(lformat!("Parts are not supported yet")),
            }
            for token in v {
                content.push_str(&self.parse_token(token));
            }
        }

        let template = try!(compile_str(odt::CONTENT,
                                        &self.book.source,
                                        "could not compile template for content.xml"));
        let data = try!(self.book.get_metadata(|s| Ok(s.to_owned())))
            .insert_str("content", content)
            .insert_str("automatic_styles", &self.automatic_styles)
            .build();

        let mut res: Vec<u8> = vec![];
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => panic!(lformat!("generated content.xml was not utf-8 valid")),
            Ok(res) => Ok(res),
        }
    }

    /// Transform a vector of `Token`s to Odt format
    fn render_vec(&mut self, tokens: &[Token]) -> String {
        let mut res = String::new();

        for token in tokens {
            res.push_str(&self.parse_token(&token));
        }
        res
    }

    fn parse_token(&mut self, token: &Token) -> String {
        match *token {
            Token::Str(ref text) => escape::html(self.book.clean(text.as_str(), false)).into_owned(),
            Token::Paragraph(ref vec) => {
                format!("<text:p text:style-name=\"Text_20_body\">{}</text:p>\n",
                        self.render_vec(vec))
            }
            Token::Header(n, ref vec) => {
                if n == 1 && self.current_hide {
                    return String::new();
                }
                let s = if n == 1 && self.current_numbering >= 1 {
                    let chapter = self.current_chapter;
                    self.current_chapter += 1;
                    let res = self.book.get_chapter_header(chapter, self.render_vec(vec), |s| {
                        Ok(self.render_vec(&try!(Parser::new().parse_inline(s))))
                    });
                    res.unwrap()
                } else {
                    self.render_vec(vec)
                };
                format!("<text:h text:style-name=\"Heading_20_{}\">\n{}</text:h>\n",
                        n,
                        s)
            }
            Token::Emphasis(ref vec) => {
                format!("<text:span text:style-name=\"T1\">{}</text:span>",
                        self.render_vec(vec))
            }
            Token::Strong(ref vec) => {
                format!("<text:span text:style-name=\"T2\">{}</text:span>",
                        self.render_vec(vec))
            }
            Token::List(ref vec) => format!("<text:list>\n{}</text:list>\n", self.render_vec(vec)),
            Token::OrderedList(_, ref vec) => {
                self.book
                    .logger
                    .warning(lformat!("ODT: ordered list not currently implemented for this \
                                       format, fallbacking to unordered one"));
                format!("<text:list>\n{}</text:list>\n", self.render_vec(vec))
            }
            Token::Item(ref vec) => {
                format!("<text:list-item>\n<text:p>{}</text:p></text:list-item>",
                        self.render_vec(vec))
            }
            Token::Link(ref url, _, ref vec) => {
                format!("<text:a xlink:type=\"simple\"  xlink:href=\"{}\">{}</text:a>",
                        url,
                        self.render_vec(vec))
            }
            Token::Code(ref vec) => {
                format!("<text:span text:style-name=\"Preformatted_20_Text\">{}</text:span>",
                        self.render_vec(vec))
            }
            Token::BlockQuote(ref vec) |
            Token::CodeBlock(_, ref vec) => {
                self.book
                    .logger
                    .warning(lformat!("ODT: blockquotes and codeblocks are not currently \
                                       implemented for ODT"));
                format!("<text:p text:style-name=\"Text_20_Body\">{}</text:p>\n",
                        self.render_vec(vec))
            }
            Token::SoftBreak | Token::HardBreak => String::from(" "),
            Token::Rule => String::from("<text:p /><text:p>***</text:p><text:p />"),
            Token::Image(_, _, _) |
            Token::StandaloneImage(_, _, _) => {
                self.book
                    .logger
                    .warning(lformat!("ODT: images not currently implemented for this format"));
                String::from(" ")
            }
            Token::Table(_, _) |
            Token::TableHead(_) |
            Token::TableRow(_) |
            Token::TableCell(_) => {
                self.book
                    .logger
                    .warning(lformat!("ODT: tables are not currently implemented for this format"));
                String::from(" ")
            }
            Token::Footnote(_) => {
                self.book
                    .logger
                    .warning(lformat!("ODT: footnotes are not yet implemented in this format, \
                                       ignoring {:?}",
                                      token));
                String::new()
            }
            Token::Annotation(_, ref vec) => self.render_vec(vec),
            Token::__NonExhaustive => unreachable!(),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Richard Diamond & contributors.
//
// This file is part of the Rust PPApi project.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use super::{Callback, Resource, FileSliceRef, Instance, ToStringVar, ToVar, Code};
use super::ppb::{get_url_loader, get_url_request};
use ppb::{URLRequestInfoIf, URLResponseInfoIf, URLLoaderIf};
use std::{fmt, default};
use std::io::IoResult;
use collections::enum_set::{CLike, EnumSet};
use http::header::Headers;
use super::ffi;
use super::ffi::bool_to_var;
use iurl::Url;

#[deriving(Hash, Eq, PartialEq, Show)] pub struct UrlLoader(ffi::PP_Resource);
#[deriving(Hash, Eq, PartialEq, Show)] pub struct UrlRequestInfo(ffi::PP_Resource);
#[deriving(Hash, Eq, PartialEq, Show)] pub struct UrlResponseInfo(ffi::PP_Resource);

impl_resource_for!(UrlLoader ResourceType::UrlLoaderRes);
impl_resource_for!(UrlRequestInfo ResourceType::UrlRequestInfoRes);
impl_resource_for!(UrlResponseInfo ResourceType::UrlResponseInfoRes);

pub type RequestProperties = EnumSet<RequestProperties_>;
#[deriving(Eq, PartialEq, Clone, Hash, Copy)]
pub enum RequestProperties_ {
    AllowCrossOriginRequests,
    AllowCredentials,
    RecordUploadProgress,
    RecordDownloadProgress,
    FollowRedirects,
    StreamToFile,
}
impl CLike for RequestProperties_ {
    fn to_uint(&self) -> uint {
        match self {
            &RequestProperties_::AllowCrossOriginRequests => 0,
            &RequestProperties_::AllowCredentials => 1,
            &RequestProperties_::RecordUploadProgress => 2,
            &RequestProperties_::RecordDownloadProgress => 3,
            &RequestProperties_::FollowRedirects => 4,
            &RequestProperties_::StreamToFile => 5,
        }
    }
    fn from_uint(v: uint) -> RequestProperties_ {
        match v {
            0 => RequestProperties_::AllowCrossOriginRequests,
            1 => RequestProperties_::AllowCredentials,
            2 => RequestProperties_::RecordUploadProgress,
            3 => RequestProperties_::RecordDownloadProgress,
            4 => RequestProperties_::FollowRedirects,
            5 => RequestProperties_::StreamToFile,
            _ => unreachable!(),
        }
    }
}
impl RequestProperties_ {
    fn to_ffi(&self) -> ffi::PP_URLRequestProperty {
        match self {
            &RequestProperties_::AllowCrossOriginRequests =>
                ffi::PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS,
            &RequestProperties_::AllowCredentials =>
                ffi::PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS,
            &RequestProperties_::RecordUploadProgress =>
                ffi::PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS,
            &RequestProperties_::RecordDownloadProgress =>
                ffi::PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS,
            &RequestProperties_::FollowRedirects =>
                ffi::PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS,
            &RequestProperties_::StreamToFile =>
                ffi::PP_URLREQUESTPROPERTY_STREAMTOFILE,
        }
    }
}
#[deriving(Clone)]
pub enum Body {
    File(FileSliceRef, Option<super::Time>),
    Blob(Vec<u8>),
}
#[deriving(Clone, Eq, PartialEq, Hash, Copy)]
pub enum Method {
    Get,
    Post,
}
impl fmt::Show for Method {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Method::Get => f.pad("GET"),
            &Method::Post => f.pad("POST"),
        }
    }
}
impl default::Default for Method {
    fn default() -> Method {
        Method::Get
    }
}
#[deriving(Clone)]
pub struct RequestInfo {
    pub url: Url,

    pub method: Method,

    pub prefetch_buffer: Option<(i32, i32)>,
    properties: RequestProperties,
    set_props:  RequestProperties,

    pub body: Vec<Body>,

    pub headers: Headers,
}
impl RequestInfo {
    fn clear_bit(bitfield: RequestProperties, prop: RequestProperties_) -> RequestProperties {
        let mut new = EnumSet::new();
        for p in bitfield
            .iter()
            .filter(|&p| p != prop ) {
                new.insert(p);
            }
        new
    }
    pub fn set_prop(&mut self, prop: RequestProperties_, bit: bool) {
        self.set_props.insert(prop);
        self.set_prop_value(prop, bit);
    }
    // unsets the 'this property is set' bit. Doesn't clear the actual property value bit.
    pub fn unset_prop(&mut self, prop: RequestProperties_) -> bool {
        let was_set = self.set_props.contains(&prop);
        self.set_props = RequestInfo::clear_bit(self.set_props, prop);
        was_set
    }

    // set the property value, but don't set the 'this property is set' bit.
    pub fn set_prop_value(&mut self, prop: RequestProperties_, bit: bool) -> bool {
        let mut new = RequestInfo::clear_bit(self.properties, prop);
        if bit {
            new.insert(prop);
        }

        let was_set = self.properties.contains(&prop);
        self.properties = new;
        was_set
    }

    // todo remove those asserts.
    pub fn to_ffi(self) -> IoResult<UrlRequestInfo> {
        let instance = Instance::current();
        let request = get_url_request();
        let res = instance.create_url_request_info().unwrap();
        let set_true = self.set_props.intersection(self.properties);
        let set_false = self.set_props - set_true;

        let true_var = unsafe { bool_to_var(1) };
        let false_var = unsafe { bool_to_var(0) };

        for prop in set_true.iter() {
            let set = request.property(res.unwrap(), prop.to_ffi(), true_var);
            assert!(set);
        }
        for prop in set_false.iter() {
            let set = request.property(res.unwrap(), prop.to_ffi(), false_var);
            assert!(set);
        }
        let RequestInfo {
            body, headers, url, method, ..
        } = self;
        for body in body.into_iter() {
            let success = match body {
                Body::File(FileSliceRef(file, start_opt, len_opt), time) => {
                    request.append_file_to_body(res.unwrap(),
                                                file.unwrap(),
                                                start_opt,
                                                len_opt,
                                                time)
                }
                Body::Blob(blob) => {
                    request.append_blob_to_body(res.unwrap(),
                                                &blob)
                }
            };
            assert!(success);
        }
        let headers_str = headers.to_string();
        let headers_str = headers_str.to_string_var();
        let success = request.property(res.unwrap(),
                                       ffi::PP_URLREQUESTPROPERTY_HEADERS,
                                       headers_str.to_var());

        let url = url.to_string().to_string_var();
        let success = success && request.property(res.unwrap(),
                                                  ffi::PP_URLREQUESTPROPERTY_URL,
                                                  url.to_var());

        let method = method.to_string().to_string_var();
        let success = success && request.property(res.unwrap(),
                                                  ffi::PP_URLREQUESTPROPERTY_METHOD,
                                                  method.to_var());
        assert!(success);
        Ok(res)
    }
}

#[deriving(Clone, Hash, Eq, PartialEq)]
pub struct OpenedUrlLoader(UrlLoader);
impl OpenedUrlLoader {
    fn unwrap_loader<'a>(&'a self) -> &'a UrlLoader {
        let &OpenedUrlLoader(ref inner) = self;
        inner
    }
    pub fn download_progress(&self) -> Option<(i64, i64)> {
        use std::mem;
        let mut bytes_sent = unsafe { mem::uninitialized() };
        let mut total_sent = unsafe { mem::uninitialized() };

        let f = get_url_loader().GetDownloadProgress.unwrap();
        if !f(self.unwrap_loader().unwrap(), &mut bytes_sent, &mut total_sent) != 0 {
            None
        } else {
            Some((bytes_sent as i64, total_sent as i64))
        }
    }
}
impl Resource for OpenedUrlLoader {
    fn unwrap(&self) -> ffi::PP_Resource {
        self.unwrap_loader().unwrap()
    }
    fn type_of(&self) -> super::ResourceType {
        self.unwrap_loader().type_of()
    }
}

impl UrlLoader {
    // TODO: this is messy. Do it generically.
    pub fn open<F: FnOnce<(Code, OpenedUrlLoader),()> + Send>(&self,
                                                              ffi_info: UrlRequestInfo,
                                                              callback: F) -> super::Result<OpenedUrlLoader> {
        let loader = get_url_loader();
        let open_loader = OpenedUrlLoader(self.clone());
        let open_loader2 = open_loader.clone();
        let cb = move |: c: Code| {
            callback(c, open_loader2);
        };
        loader.open(self.unwrap(),
                    ffi_info.unwrap(),
                    cb.to_ffi_callback())
            .map(|_| open_loader.clone() )
    }

}
<commit_msg>Use Method from hyper.<commit_after>// Copyright (c) 2014 Richard Diamond & contributors.
//
// This file is part of the Rust PPApi project.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use super::{Callback, Resource, FileSliceRef, Instance, ToStringVar, ToVar, Code};
use super::ppb::{get_url_loader, get_url_request};
use ppb::{URLRequestInfoIf, URLResponseInfoIf, URLLoaderIf};
use std::io::IoResult;
use collections::enum_set::{CLike, EnumSet};
use http;
use http::header::Headers;
use super::ffi;
use super::ffi::bool_to_var;
use iurl::Url;

#[deriving(Hash, Eq, PartialEq, Show)] pub struct UrlLoader(ffi::PP_Resource);
#[deriving(Hash, Eq, PartialEq, Show)] pub struct UrlRequestInfo(ffi::PP_Resource);
#[deriving(Hash, Eq, PartialEq, Show)] pub struct UrlResponseInfo(ffi::PP_Resource);

impl_resource_for!(UrlLoader ResourceType::UrlLoaderRes);
impl_resource_for!(UrlRequestInfo ResourceType::UrlRequestInfoRes);
impl_resource_for!(UrlResponseInfo ResourceType::UrlResponseInfoRes);

pub type RequestProperties = EnumSet<RequestProperties_>;
#[deriving(Eq, PartialEq, Clone, Hash, Copy)]
pub enum RequestProperties_ {
    AllowCrossOriginRequests,
    AllowCredentials,
    RecordUploadProgress,
    RecordDownloadProgress,
    FollowRedirects,
    StreamToFile,
}
impl CLike for RequestProperties_ {
    fn to_uint(&self) -> uint {
        match self {
            &RequestProperties_::AllowCrossOriginRequests => 0,
            &RequestProperties_::AllowCredentials => 1,
            &RequestProperties_::RecordUploadProgress => 2,
            &RequestProperties_::RecordDownloadProgress => 3,
            &RequestProperties_::FollowRedirects => 4,
            &RequestProperties_::StreamToFile => 5,
        }
    }
    fn from_uint(v: uint) -> RequestProperties_ {
        match v {
            0 => RequestProperties_::AllowCrossOriginRequests,
            1 => RequestProperties_::AllowCredentials,
            2 => RequestProperties_::RecordUploadProgress,
            3 => RequestProperties_::RecordDownloadProgress,
            4 => RequestProperties_::FollowRedirects,
            5 => RequestProperties_::StreamToFile,
            _ => unreachable!(),
        }
    }
}
impl RequestProperties_ {
    fn to_ffi(&self) -> ffi::PP_URLRequestProperty {
        match self {
            &RequestProperties_::AllowCrossOriginRequests =>
                ffi::PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS,
            &RequestProperties_::AllowCredentials =>
                ffi::PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS,
            &RequestProperties_::RecordUploadProgress =>
                ffi::PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS,
            &RequestProperties_::RecordDownloadProgress =>
                ffi::PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS,
            &RequestProperties_::FollowRedirects =>
                ffi::PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS,
            &RequestProperties_::StreamToFile =>
                ffi::PP_URLREQUESTPROPERTY_STREAMTOFILE,
        }
    }
}
#[deriving(Clone)]
pub enum Body {
    File(FileSliceRef, Option<super::Time>),
    Blob(Vec<u8>),
}

pub type Method = http::method::Method;

#[deriving(Clone)]
pub struct RequestInfo {
    pub url: Url,

    pub method: Method,

    pub prefetch_buffer: Option<(i32, i32)>,
    properties: RequestProperties,
    set_props:  RequestProperties,

    pub body: Vec<Body>,

    pub headers: Headers,
}
impl RequestInfo {
    fn clear_bit(bitfield: RequestProperties, prop: RequestProperties_) -> RequestProperties {
        let mut new = EnumSet::new();
        for p in bitfield
            .iter()
            .filter(|&p| p != prop ) {
                new.insert(p);
            }
        new
    }
    pub fn set_prop(&mut self, prop: RequestProperties_, bit: bool) {
        self.set_props.insert(prop);
        self.set_prop_value(prop, bit);
    }
    // unsets the 'this property is set' bit. Doesn't clear the actual property value bit.
    pub fn unset_prop(&mut self, prop: RequestProperties_) -> bool {
        let was_set = self.set_props.contains(&prop);
        self.set_props = RequestInfo::clear_bit(self.set_props, prop);
        was_set
    }

    // set the property value, but don't set the 'this property is set' bit.
    pub fn set_prop_value(&mut self, prop: RequestProperties_, bit: bool) -> bool {
        let mut new = RequestInfo::clear_bit(self.properties, prop);
        if bit {
            new.insert(prop);
        }

        let was_set = self.properties.contains(&prop);
        self.properties = new;
        was_set
    }

    // todo remove those asserts.
    pub fn to_ffi(self) -> IoResult<UrlRequestInfo> {
        let instance = Instance::current();
        let request = get_url_request();
        let res = instance.create_url_request_info().unwrap();
        let set_true = self.set_props.intersection(self.properties);
        let set_false = self.set_props - set_true;

        let true_var = unsafe { bool_to_var(1) };
        let false_var = unsafe { bool_to_var(0) };

        for prop in set_true.iter() {
            let set = request.property(res.unwrap(), prop.to_ffi(), true_var);
            assert!(set);
        }
        for prop in set_false.iter() {
            let set = request.property(res.unwrap(), prop.to_ffi(), false_var);
            assert!(set);
        }
        let RequestInfo {
            body, headers, url, method, ..
        } = self;
        for body in body.into_iter() {
            let success = match body {
                Body::File(FileSliceRef(file, start_opt, len_opt), time) => {
                    request.append_file_to_body(res.unwrap(),
                                                file.unwrap(),
                                                start_opt,
                                                len_opt,
                                                time)
                }
                Body::Blob(blob) => {
                    request.append_blob_to_body(res.unwrap(),
                                                &blob)
                }
            };
            assert!(success);
        }
        let headers_str = headers.to_string();
        let headers_str = headers_str.to_string_var();
        let success = request.property(res.unwrap(),
                                       ffi::PP_URLREQUESTPROPERTY_HEADERS,
                                       headers_str.to_var());

        let url = url.to_string().to_string_var();
        let success = success && request.property(res.unwrap(),
                                                  ffi::PP_URLREQUESTPROPERTY_URL,
                                                  url.to_var());

        let method = method.to_string().to_string_var();
        let success = success && request.property(res.unwrap(),
                                                  ffi::PP_URLREQUESTPROPERTY_METHOD,
                                                  method.to_var());
        assert!(success);
        Ok(res)
    }
}

#[deriving(Clone, Hash, Eq, PartialEq)]
pub struct OpenedUrlLoader(UrlLoader);
impl OpenedUrlLoader {
    fn unwrap_loader<'a>(&'a self) -> &'a UrlLoader {
        let &OpenedUrlLoader(ref inner) = self;
        inner
    }
    pub fn download_progress(&self) -> Option<(i64, i64)> {
        use std::mem;
        let mut bytes_sent = unsafe { mem::uninitialized() };
        let mut total_sent = unsafe { mem::uninitialized() };

        let f = get_url_loader().GetDownloadProgress.unwrap();
        if !f(self.unwrap_loader().unwrap(), &mut bytes_sent, &mut total_sent) != 0 {
            None
        } else {
            Some((bytes_sent as i64, total_sent as i64))
        }
    }
}
impl Resource for OpenedUrlLoader {
    fn unwrap(&self) -> ffi::PP_Resource {
        self.unwrap_loader().unwrap()
    }
    fn type_of(&self) -> super::ResourceType {
        self.unwrap_loader().type_of()
    }
}

impl UrlLoader {
    // TODO: this is messy. Do it generically.
    pub fn open<F: FnOnce<(Code, OpenedUrlLoader),()> + Send>(&self,
                                                              ffi_info: UrlRequestInfo,
                                                              callback: F) -> super::Result<OpenedUrlLoader> {
        let loader = get_url_loader();
        let open_loader = OpenedUrlLoader(self.clone());
        let open_loader2 = open_loader.clone();
        let cb = move |: c: Code| {
            callback(c, open_loader2);
        };
        loader.open(self.unwrap(),
                    ffi_info.unwrap(),
                    cb.to_ffi_callback())
            .map(|_| open_loader.clone() )
    }

}
<|endoftext|>


<commit_before>use std;
use std::fmt::{Debug, Formatter};
use std::ops::*;

const P: i64 = 1_000_000_007;

/// Calculates `x^n`. O(log n) time.
/// By Fermat's little theorem, `x^(-1) = pow(x, P - 2)`.
pub fn pow(x: i64, n: i64) -> i64 {
    let (mut x, mut y, mut n) = (x % P, 1_i64, n);
    while n > 0 {
        if n % 2 != 0 {
            y = (y * x) % P;
            n -= 1;
        }

        x = (x * x) % P;
        n /= 2;
    }
    y
}

/// Calculates `a^(-1)` for each `a` in `1..n`.
pub fn inv_dp(n: usize) -> Vec<i64> {
    let mut dp = vec![0; n];
    if n >= 2 {
        dp[1] = 1;
        for i in 2..n {
            let mut z = P - dp[(P % i as i64) as usize];
            z %= P;
            z *= P / i as i64;
            z %= P;
            dp[i] = z;
        }
    }
    dp
}

/// Represents an element of finite field.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
struct Finite<T>(T);

impl<T: Debug> Debug for Finite<T> {
    fn fmt(&self, formatter: &mut Formatter) -> std::fmt::Result {
        formatter.write_fmt(format_args!("{:?}", self.0))
    }
}

trait Normalize {
    fn normalize(&mut self);
}

impl<T> From<T> for Finite<T>
where
    Finite<T>: Normalize,
{
    fn from(value: T) -> Self {
        let mut it = Finite(value);
        it.normalize();
        it
    }
}

// Derive binary operation trait from the `FooAssign` impl.
// Define `x + y` as `{ let mut x = x.clone(); x += y; x }`.
macro_rules! impl_binary_op_for_finite {
    ($op_trait:ident, $op:ident, $assign_trait:ident, $assign:ident) => {
        impl<T: $op_trait<T, Output = T>> $op_trait<T> for Finite<T>
        where
            Finite<T>: Clone + $assign_trait<T>,
        {
            type Output = Self;

            fn $op(self, other: T) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }

        impl<T: $op_trait<T, Output = T>> $op_trait<Finite<T>> for Finite<T>
        where
            Finite<T>: Clone + $assign_trait<Finite<T>>,
        {
            type Output = Self;

            fn $op(self, other: Self) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }
    };
}

// Derive assign operation trait by unwrapping the right hand side.
macro_rules! impl_binary_op_assign_with_finite_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl<T> $op_trait<Finite<T>> for Finite<T>
        where
            Finite<T>: $op_trait<T>,
        {
            fn $op(&mut self, other: Self) {
                self.$op(other.0);
            }
        }
    };
}

// Derive assign operation trait from impl for inner type.
macro_rules! impl_binary_op_assign_with_inner_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl<T: $op_trait<T>> $op_trait<T> for Finite<T>
        where
            Finite<T>: Normalize,
        {
            fn $op(&mut self, other: T) {
                let mut other = Finite::from(other);
                other.normalize();
                (self.0).$op(other.0);
                self.normalize();
            }
        }
    };
}

impl_binary_op_for_finite! {Add, add, AddAssign, add_assign}
impl_binary_op_for_finite! {Sub, sub, SubAssign, sub_assign}
impl_binary_op_for_finite! {Mul, mul, MulAssign, mul_assign}
impl_binary_op_for_finite! {Div, div, DivAssign, div_assign}
impl_binary_op_assign_with_inner_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_inner_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_inner_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_finite_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_finite_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {DivAssign, div_assign}

impl Finite<i64> {
    fn pow(self, e: i64) -> Self {
        pow(self.0, e).into()
    }
}

impl Normalize for Finite<i64> {
    fn normalize(&mut self) {
        self.0 %= P;
        self.0 += P;
        self.0 %= P;
    }
}

impl DivAssign<i64> for Finite<i64> {
    fn div_assign(&mut self, other: i64) {
        *self *= Self::from(other).pow(P - 2);
    }
}

#[cfg(test)]
mod tests {
    use super::{inv_dp, pow, Finite, P};
    use std;

    #[test]
    fn test_pow_edges() {
        assert_eq!(pow(0, 0), 1);
        assert_eq!(pow(2, 0), 1);
        assert_eq!(pow(3, 1), 3);
        assert_eq!(pow(5, 6), (5 * 5 * 5) * (5 * 5 * 5));
        assert_eq!(pow(std::i64::MAX % P, std::i64::MAX), 856225998);
    }

    #[test]
    fn test_pow_small() {
        for x in 0..100_i64 {
            for n in 0..100_i64 {
                let actual = pow(x, n);
                let expected = (0..n).fold(1_i64, |acc, _| (acc * x) % P);
                assert_eq!(actual, expected, "{}^{}", x, n);
            }
        }
    }

    #[test]
    fn test_inv_dp() {
        let n = 10000;
        let dp = inv_dp(n);
        for i in 1..n {
            let mut z = dp[i] * i as i64;
            z %= P;
            z += P;
            z %= P;
            assert_eq!(z, 1);
        }
    }

    #[test]
    fn test_finite() {
        let x = Finite::from(P + 2);

        // `from` should normalize the value.
        assert_eq!(x.0, 2);

        // Operations.
        assert_eq!(x + 7, (2 + 7).into());
        assert_eq!(x - 7, (P + (2 - 7)).into());
        assert_eq!(x * 3, (2 * 3).into());
        assert_eq!((x / 11) * 11, 2.into());

        assert_eq!(x + Finite::from(7), (2 + 7).into());
        assert_eq!(x - Finite::from(7), (P + (2 - 7)).into());
        assert_eq!(x * Finite::from(3), (2 * 3).into());
        assert_eq!((x / Finite::from(11)) * 11, 2.into());

        let mut x = x;
        x += 7;
        assert_eq!(x, 9.into());
        x -= 5;
        assert_eq!(x, 4.into());
        x *= 6;
        assert_eq!(x, 24.into());
        x /= 3;
        assert_eq!(x, 8.into());
    }
}
<commit_msg>feat: Derive `Default`<commit_after>use std;
use std::fmt::{Debug, Formatter};
use std::ops::*;

const P: i64 = 1_000_000_007;

/// Calculates `x^n`. O(log n) time.
/// By Fermat's little theorem, `x^(-1) = pow(x, P - 2)`.
pub fn pow(x: i64, n: i64) -> i64 {
    let (mut x, mut y, mut n) = (x % P, 1_i64, n);
    while n > 0 {
        if n % 2 != 0 {
            y = (y * x) % P;
            n -= 1;
        }

        x = (x * x) % P;
        n /= 2;
    }
    y
}

/// Calculates `a^(-1)` for each `a` in `1..n`.
pub fn inv_dp(n: usize) -> Vec<i64> {
    let mut dp = vec![0; n];
    if n >= 2 {
        dp[1] = 1;
        for i in 2..n {
            let mut z = P - dp[(P % i as i64) as usize];
            z %= P;
            z *= P / i as i64;
            z %= P;
            dp[i] = z;
        }
    }
    dp
}

/// Represents an element of finite field.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
struct Finite<T>(T);

impl<T: Debug> Debug for Finite<T> {
    fn fmt(&self, formatter: &mut Formatter) -> std::fmt::Result {
        formatter.write_fmt(format_args!("{:?}", self.0))
    }
}

trait Normalize {
    fn normalize(&mut self);
}

impl<T> From<T> for Finite<T>
where
    Finite<T>: Normalize,
{
    fn from(value: T) -> Self {
        let mut it = Finite(value);
        it.normalize();
        it
    }
}

// Derive binary operation trait from the `FooAssign` impl.
// Define `x + y` as `{ let mut x = x.clone(); x += y; x }`.
macro_rules! impl_binary_op_for_finite {
    ($op_trait:ident, $op:ident, $assign_trait:ident, $assign:ident) => {
        impl<T: $op_trait<T, Output = T>> $op_trait<T> for Finite<T>
        where
            Finite<T>: Clone + $assign_trait<T>,
        {
            type Output = Self;

            fn $op(self, other: T) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }

        impl<T: $op_trait<T, Output = T>> $op_trait<Finite<T>> for Finite<T>
        where
            Finite<T>: Clone + $assign_trait<Finite<T>>,
        {
            type Output = Self;

            fn $op(self, other: Self) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }
    };
}

// Derive assign operation trait by unwrapping the right hand side.
macro_rules! impl_binary_op_assign_with_finite_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl<T> $op_trait<Finite<T>> for Finite<T>
        where
            Finite<T>: $op_trait<T>,
        {
            fn $op(&mut self, other: Self) {
                self.$op(other.0);
            }
        }
    };
}

// Derive assign operation trait from impl for inner type.
macro_rules! impl_binary_op_assign_with_inner_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl<T: $op_trait<T>> $op_trait<T> for Finite<T>
        where
            Finite<T>: Normalize,
        {
            fn $op(&mut self, other: T) {
                let mut other = Finite::from(other);
                other.normalize();
                (self.0).$op(other.0);
                self.normalize();
            }
        }
    };
}

impl_binary_op_for_finite! {Add, add, AddAssign, add_assign}
impl_binary_op_for_finite! {Sub, sub, SubAssign, sub_assign}
impl_binary_op_for_finite! {Mul, mul, MulAssign, mul_assign}
impl_binary_op_for_finite! {Div, div, DivAssign, div_assign}
impl_binary_op_assign_with_inner_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_inner_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_inner_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_finite_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_finite_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {DivAssign, div_assign}

impl Finite<i64> {
    fn pow(self, e: i64) -> Self {
        pow(self.0, e).into()
    }
}

impl Normalize for Finite<i64> {
    fn normalize(&mut self) {
        self.0 %= P;
        self.0 += P;
        self.0 %= P;
    }
}

impl DivAssign<i64> for Finite<i64> {
    fn div_assign(&mut self, other: i64) {
        *self *= Self::from(other).pow(P - 2);
    }
}

#[cfg(test)]
mod tests {
    use super::{inv_dp, pow, Finite, P};
    use std;

    #[test]
    fn test_pow_edges() {
        assert_eq!(pow(0, 0), 1);
        assert_eq!(pow(2, 0), 1);
        assert_eq!(pow(3, 1), 3);
        assert_eq!(pow(5, 6), (5 * 5 * 5) * (5 * 5 * 5));
        assert_eq!(pow(std::i64::MAX % P, std::i64::MAX), 856225998);
    }

    #[test]
    fn test_pow_small() {
        for x in 0..100_i64 {
            for n in 0..100_i64 {
                let actual = pow(x, n);
                let expected = (0..n).fold(1_i64, |acc, _| (acc * x) % P);
                assert_eq!(actual, expected, "{}^{}", x, n);
            }
        }
    }

    #[test]
    fn test_inv_dp() {
        let n = 10000;
        let dp = inv_dp(n);
        for i in 1..n {
            let mut z = dp[i] * i as i64;
            z %= P;
            z += P;
            z %= P;
            assert_eq!(z, 1);
        }
    }

    #[test]
    fn test_finite() {
        let x = Finite::from(P + 2);

        // `from` should normalize the value.
        assert_eq!(x.0, 2);

        // Operations.
        assert_eq!(x + 7, (2 + 7).into());
        assert_eq!(x - 7, (P + (2 - 7)).into());
        assert_eq!(x * 3, (2 * 3).into());
        assert_eq!((x / 11) * 11, 2.into());

        assert_eq!(x + Finite::from(7), (2 + 7).into());
        assert_eq!(x - Finite::from(7), (P + (2 - 7)).into());
        assert_eq!(x * Finite::from(3), (2 * 3).into());
        assert_eq!((x / Finite::from(11)) * 11, 2.into());

        let mut x = x;
        x += 7;
        assert_eq!(x, 9.into());
        x -= 5;
        assert_eq!(x, 4.into());
        x *= 6;
        assert_eq!(x, 24.into());
        x /= 3;
        assert_eq!(x, 8.into());
    }
}
<|endoftext|>


<commit_before>use std;
use std::fmt::{Debug, Display, Formatter};
use std::ops::*;

const P: i64 = 1_000_000_007;

/// Calculates `x^n`. O(log n) time.
/// By Fermat's little theorem, `x^(-1) = pow(x, P - 2)`.
pub fn pow(x: i64, n: i64) -> i64 {
    let (mut x, mut y, mut n) = (x % P, 1_i64, n);
    while n > 0 {
        if n % 2 != 0 {
            y = (y * x) % P;
            n -= 1;
        }

        x = (x * x) % P;
        n /= 2;
    }
    y
}

/// Calculates `1/a` for each `a` in `1..n`.
/// Use `P = floor(P / k) * k + P % k` for proof.
pub fn inv_dp(n: usize) -> Vec<i64> {
    let mut dp = vec![0; n];
    if n >= 2 {
        dp[1] = 1;
        for i in 2..n {
            let mut z = P - dp[(P % i as i64) as usize];
            z %= P;
            z *= P / i as i64;
            z %= P;
            dp[i] = z;
        }
    }
    dp
}

/// Represents an element of finite field.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
struct Finite<T>(T);

impl<T: Debug> Debug for Finite<T> {
    fn fmt(&self, formatter: &mut Formatter) -> std::fmt::Result {
        formatter.write_fmt(format_args!("{:?}", self.0))
    }
}

impl<T: Display> Display for Finite<T> {
    fn fmt(&self, formatter: &mut Formatter) -> std::fmt::Result {
        formatter.write_fmt(format_args!("{}", self.0))
    }
}

trait Normalize {
    fn normalize(&mut self);
}

impl<T> From<T> for Finite<T>
where
    Finite<T>: Normalize,
{
    fn from(value: T) -> Self {
        let mut it = Finite(value);
        it.normalize();
        it
    }
}

// Derive binary operation trait from the `FooAssign` impl.
// Define `x + y` as `{ let mut x = x.clone(); x += y; x }`.
macro_rules! impl_binary_op_for_finite {
    ($op_trait:ident, $op:ident, $assign_trait:ident, $assign:ident) => {
        impl<T: $op_trait<T, Output = T>> $op_trait<T> for Finite<T>
        where
            Finite<T>: Clone + $assign_trait<T>,
        {
            type Output = Self;

            fn $op(self, other: T) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }

        impl<T: $op_trait<T, Output = T>> $op_trait<Finite<T>> for Finite<T>
        where
            Finite<T>: Clone + $assign_trait<Finite<T>>,
        {
            type Output = Self;

            fn $op(self, other: Self) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }
    };
}

// Derive assign operation trait by unwrapping the right hand side.
macro_rules! impl_binary_op_assign_with_finite_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl<T> $op_trait<Finite<T>> for Finite<T>
        where
            Finite<T>: $op_trait<T>,
        {
            fn $op(&mut self, other: Self) {
                self.$op(other.0);
            }
        }
    };
}

// Derive assign operation trait from impl for inner type.
macro_rules! impl_binary_op_assign_with_inner_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl<T: $op_trait<T>> $op_trait<T> for Finite<T>
        where
            Finite<T>: Normalize,
        {
            fn $op(&mut self, other: T) {
                let mut other = Finite::from(other);
                other.normalize();
                (self.0).$op(other.0);
                self.normalize();
            }
        }
    };
}

impl_binary_op_for_finite! {Add, add, AddAssign, add_assign}
impl_binary_op_for_finite! {Sub, sub, SubAssign, sub_assign}
impl_binary_op_for_finite! {Mul, mul, MulAssign, mul_assign}
impl_binary_op_for_finite! {Div, div, DivAssign, div_assign}
impl_binary_op_assign_with_inner_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_inner_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_inner_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_finite_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_finite_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {DivAssign, div_assign}

impl Finite<i64> {
    fn pow(self, e: i64) -> Self {
        pow(self.0, e).into()
    }
}

impl Normalize for Finite<i64> {
    fn normalize(&mut self) {
        self.0 %= P;
        self.0 += P;
        self.0 %= P;
    }
}

impl DivAssign<i64> for Finite<i64> {
    fn div_assign(&mut self, other: i64) {
        *self *= Self::from(other).pow(P - 2);
    }
}

#[cfg(test)]
mod tests {
    use super::{inv_dp, pow, Finite, P};
    use std;

    #[test]
    fn test_pow_edges() {
        assert_eq!(pow(0, 0), 1);
        assert_eq!(pow(2, 0), 1);
        assert_eq!(pow(3, 1), 3);
        assert_eq!(pow(5, 6), (5 * 5 * 5) * (5 * 5 * 5));
        assert_eq!(pow(std::i64::MAX % P, std::i64::MAX), 856225998);
    }

    #[test]
    fn test_pow_small() {
        for x in 0..100_i64 {
            for n in 0..100_i64 {
                let actual = pow(x, n);
                let expected = (0..n).fold(1_i64, |acc, _| (acc * x) % P);
                assert_eq!(actual, expected, "{}^{}", x, n);
            }
        }
    }

    #[test]
    fn test_inv_dp() {
        let n = 10000;
        let dp = inv_dp(n);
        for i in 1..n {
            let mut z = dp[i] * i as i64;
            z %= P;
            z += P;
            z %= P;
            assert_eq!(z, 1);
        }
    }

    #[test]
    fn test_finite() {
        let x = Finite::from(P + 2);

        // `from` should normalize the value.
        assert_eq!(x.0, 2);

        // Operations.
        assert_eq!(x + 7, (2 + 7).into());
        assert_eq!(x - 7, (P + (2 - 7)).into());
        assert_eq!(x * 3, (2 * 3).into());
        assert_eq!((x / 11) * 11, 2.into());

        assert_eq!(x + Finite::from(7), (2 + 7).into());
        assert_eq!(x - Finite::from(7), (P + (2 - 7)).into());
        assert_eq!(x * Finite::from(3), (2 * 3).into());
        assert_eq!((x / Finite::from(11)) * 11, 2.into());

        let mut x = x;
        x += 7;
        assert_eq!(x, 9.into());
        x -= 5;
        assert_eq!(x, 4.into());
        x *= 6;
        assert_eq!(x, 24.into());
        x /= 3;
        assert_eq!(x, 8.into());
    }
}
<commit_msg>refactor: Make `Finite` less generic<commit_after>use std;
use std::fmt::{Debug, Display, Formatter};
use std::ops::*;

const P: i64 = 1_000_000_007;

/// Calculates `x^n`. O(log n) time.
/// By Fermat's little theorem, `x^(-1) = pow(x, P - 2)`.
pub fn pow(x: i64, n: i64) -> i64 {
    let (mut x, mut y, mut n) = (x % P, 1_i64, n);
    while n > 0 {
        if n % 2 != 0 {
            y = (y * x) % P;
            n -= 1;
        }

        x = (x * x) % P;
        n /= 2;
    }
    y
}

/// Calculates `1/a` for each `a` in `1..n`.
/// Use `P = floor(P / k) * k + P % k` for proof.
pub fn inv_dp(n: usize) -> Vec<i64> {
    let mut dp = vec![0; n];
    if n >= 2 {
        dp[1] = 1;
        for i in 2..n {
            let mut z = P - dp[(P % i as i64) as usize];
            z %= P;
            z *= P / i as i64;
            z %= P;
            dp[i] = z;
        }
    }
    dp
}

/// Represents an element of finite field.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
struct Finite(i64);

impl Debug for Finite {
    fn fmt(&self, formatter: &mut Formatter) -> std::fmt::Result {
        formatter.write_fmt(format_args!("{:?}", self.0))
    }
}

impl Display for Finite {
    fn fmt(&self, formatter: &mut Formatter) -> std::fmt::Result {
        formatter.write_fmt(format_args!("{}", self.0))
    }
}

impl From<i64> for Finite {
    fn from(value: i64) -> Self {
        let mut it = Finite(value);
        it.normalize();
        it
    }
}

// Derive binary operation trait from the `FooAssign` impl.
// Define `x + y` as `{ let mut x = x.clone(); x += y; x }`.
macro_rules! impl_binary_op_for_finite {
    ($op_trait:ident, $op:ident, $assign_trait:ident, $assign:ident) => {
        impl $op_trait<i64> for Finite {
            type Output = Self;

            fn $op(self, other: i64) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }

        impl $op_trait<Finite> for Finite {
            type Output = Self;

            fn $op(self, other: Self) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }
    };
}

// Derive assign operation trait by unwrapping the right hand side.
macro_rules! impl_binary_op_assign_with_finite_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl $op_trait<Finite> for Finite {
            fn $op(&mut self, other: Self) {
                self.$op(other.0);
            }
        }
    };
}

// Derive assign operation trait from impl for inner type.
macro_rules! impl_binary_op_assign_with_inner_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl $op_trait<i64> for Finite {
            fn $op(&mut self, other: i64) {
                let mut other = Finite::from(other);
                other.normalize();
                (self.0).$op(other.0);
                self.normalize();
            }
        }
    };
}

impl_binary_op_for_finite! {Add, add, AddAssign, add_assign}
impl_binary_op_for_finite! {Sub, sub, SubAssign, sub_assign}
impl_binary_op_for_finite! {Mul, mul, MulAssign, mul_assign}
impl_binary_op_for_finite! {Div, div, DivAssign, div_assign}
impl_binary_op_assign_with_inner_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_inner_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_inner_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_finite_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_finite_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {DivAssign, div_assign}

impl Finite {
    fn pow(self, e: i64) -> Self {
        pow(self.0, e).into()
    }

    fn normalize(&mut self) {
        self.0 %= P;
        self.0 += P;
        self.0 %= P;
    }
}

impl DivAssign<i64> for Finite {
    fn div_assign(&mut self, other: i64) {
        *self *= Self::from(other).pow(P - 2);
    }
}

#[cfg(test)]
mod tests {
    use super::{inv_dp, pow, Finite, P};
    use std;

    #[test]
    fn test_pow_edges() {
        assert_eq!(pow(0, 0), 1);
        assert_eq!(pow(2, 0), 1);
        assert_eq!(pow(3, 1), 3);
        assert_eq!(pow(5, 6), (5 * 5 * 5) * (5 * 5 * 5));
        assert_eq!(pow(std::i64::MAX % P, std::i64::MAX), 856225998);
    }

    #[test]
    fn test_pow_small() {
        for x in 0..100_i64 {
            for n in 0..100_i64 {
                let actual = pow(x, n);
                let expected = (0..n).fold(1_i64, |acc, _| (acc * x) % P);
                assert_eq!(actual, expected, "{}^{}", x, n);
            }
        }
    }

    #[test]
    fn test_inv_dp() {
        let n = 10000;
        let dp = inv_dp(n);
        for i in 1..n {
            let mut z = dp[i] * i as i64;
            z %= P;
            z += P;
            z %= P;
            assert_eq!(z, 1);
        }
    }

    #[test]
    fn test_finite() {
        let x = Finite::from(P + 2);

        // `from` should normalize the value.
        assert_eq!(x.0, 2);

        // Operations.
        assert_eq!(x + 7, (2 + 7).into());
        assert_eq!(x - 7, (P + (2 - 7)).into());
        assert_eq!(x * 3, (2 * 3).into());
        assert_eq!((x / 11) * 11, 2.into());

        assert_eq!(x + Finite::from(7), (2 + 7).into());
        assert_eq!(x - Finite::from(7), (P + (2 - 7)).into());
        assert_eq!(x * Finite::from(3), (2 * 3).into());
        assert_eq!((x / Finite::from(11)) * 11, 2.into());

        let mut x = x;
        x += 7;
        assert_eq!(x, 9.into());
        x -= 5;
        assert_eq!(x, 4.into());
        x *= 6;
        assert_eq!(x, 24.into());
        x /= 3;
        assert_eq!(x, 8.into());
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::sync::Arc;
use std::thread::JoinHandle;
use std::process::Command;

use config::Config;

pub struct ProcessHandler {
    pub config: Config,
}

impl ProcessHandler {
    pub fn new(config: Config) -> ProcessHandler {
        ProcessHandler {config: config}
    }

    pub fn execute(self) -> JoinHandle<()> {
        let config = Arc::new(self.config).clone();
        thread::spawn(move|| {
            loop {
                println!("Launching {:?} using command: {:?}, with args: {:?}, from directory: {:?}", config.name, config.cmd, config.args, config.cwd);
                let mut child = Command::new(&config.cmd)
                            .current_dir(&config.cwd)
                            .spawn()
                            .unwrap_or_else(|e| { panic!("failed to execute child: {}", e) });

                child.wait().unwrap_or_else(|e| { panic!("failed to wait on child: {}", e) });
            }
        })
    }
}<commit_msg>passing arguments to Command from Config<commit_after>use std::thread;
use std::sync::Arc;
use std::thread::JoinHandle;
use std::process::Command;

use config::Config;

pub struct ProcessHandler {
    pub config: Config,
}

impl ProcessHandler {
    pub fn new(config: Config) -> ProcessHandler {
        ProcessHandler {config: config}
    }

    pub fn execute(self) -> JoinHandle<()> {
        let config = Arc::new(self.config).clone();
        thread::spawn(move|| {
            loop {
                println!("Launching {:?} using command: {:?}, with args: {:?}, from directory: {:?}", config.name, config.cmd, config.args, config.cwd);
                let mut child = Command::new(&config.cmd)
                            .current_dir(&config.cwd)
                            .args(&config.args)
                            .spawn()
                            .unwrap_or_else(|e| { panic!("failed to execute child: {}", e) });

                child.wait().unwrap_or_else(|e| { panic!("failed to wait on child: {}", e) });
            }
        })
    }
}<|endoftext|>


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

use crate::controllers::helpers::pagination::{Page, PaginationOptions};
use crate::controllers::util::AuthenticatedUser;
use crate::models::{Crate, CrateOwnerInvitation, Rights, User};
use crate::schema::{crate_owner_invitations, crates, users};
use crate::util::errors::{forbidden, internal};
use crate::views::{
    EncodableCrateOwnerInvitation, EncodableCrateOwnerInvitationV1, EncodablePublicUser,
    InvitationResponse,
};
use chrono::{Duration, Utc};
use diesel::{pg::Pg, sql_types::Bool};
use indexmap::IndexMap;
use std::collections::{HashMap, HashSet};

/// Handles the `GET /api/v1/me/crate_owner_invitations` route.
pub fn list(req: &mut dyn RequestExt) -> EndpointResult {
    let auth = req.authenticate()?.forbid_api_token_auth()?;
    let user_id = auth.user_id();

    let PrivateListResponse {
        invitations, users, ..
    } = prepare_list(req, auth, ListFilter::InviteeId(user_id))?;

    // The schema for the private endpoints is converted to the schema used by v1 endpoints.
    let crate_owner_invitations = invitations
        .into_iter()
        .map(|private| {
            Ok(EncodableCrateOwnerInvitationV1 {
                invited_by_username: users
                    .iter()
                    .find(|u| u.id == private.inviter_id)
                    .ok_or_else(|| internal(&format!("missing user {}", private.inviter_id)))?
                    .login
                    .clone(),
                invitee_id: private.invitee_id,
                inviter_id: private.inviter_id,
                crate_name: private.crate_name,
                crate_id: private.crate_id,
                created_at: private.created_at,
                expires_at: private.expires_at,
            })
        })
        .collect::<AppResult<Vec<EncodableCrateOwnerInvitationV1>>>()?;

    #[derive(Serialize)]
    struct R {
        crate_owner_invitations: Vec<EncodableCrateOwnerInvitationV1>,
        users: Vec<EncodablePublicUser>,
    }
    Ok(req.json(&R {
        crate_owner_invitations,
        users,
    }))
}

/// Handles the `GET /api/private/crate-owner-invitations` route.
pub fn private_list(req: &mut dyn RequestExt) -> EndpointResult {
    let auth = req.authenticate()?.forbid_api_token_auth()?;

    let filter = if let Some(crate_name) = req.query().get("crate_name") {
        ListFilter::CrateName(crate_name.clone())
    } else if let Some(id) = req.query().get("invitee_id").and_then(|i| i.parse().ok()) {
        ListFilter::InviteeId(id)
    } else {
        return Err(bad_request("missing or invalid filter"));
    };

    let list = prepare_list(req, auth, filter)?;
    Ok(req.json(&list))
}

enum ListFilter {
    CrateName(String),
    InviteeId(i32),
}

fn prepare_list(
    req: &mut dyn RequestExt,
    auth: AuthenticatedUser,
    filter: ListFilter,
) -> AppResult<PrivateListResponse> {
    let pagination: PaginationOptions = PaginationOptions::builder()
        .enable_pages(false)
        .enable_seek(true)
        .gather(req)?;

    let user = auth.user();
    let conn = req.db_read_only()?;
    let config = &req.app().config;

    let mut crate_names = HashMap::new();
    let mut users = IndexMap::new();
    users.insert(user.id, user.clone());

    let sql_filter: Box<dyn BoxableExpression<crate_owner_invitations::table, Pg, SqlType = Bool>> =
        match filter {
            ListFilter::CrateName(crate_name) => {
                // Only allow crate owners to query pending invitations for their crate.
                let krate: Crate = Crate::by_name(&crate_name).first(&*conn)?;
                let owners = krate.owners(&*conn)?;
                if user.rights(req.app(), &owners)? != Rights::Full {
                    return Err(forbidden());
                }

                // Cache the crate name to avoid querying it from the database again
                crate_names.insert(krate.id, krate.name.clone());

                Box::new(crate_owner_invitations::crate_id.eq(krate.id))
            }
            ListFilter::InviteeId(invitee_id) => {
                if invitee_id != user.id {
                    return Err(forbidden());
                }
                Box::new(crate_owner_invitations::invited_user_id.eq(invitee_id))
            }
        };

    // Load all the non-expired invitations matching the filter.
    let expire_cutoff = Duration::days(config.ownership_invitations_expiration_days as i64);
    let query = crate_owner_invitations::table
        .filter(sql_filter)
        .filter(crate_owner_invitations::created_at.gt((Utc::now() - expire_cutoff).naive_utc()))
        .order_by((
            crate_owner_invitations::crate_id,
            crate_owner_invitations::invited_user_id,
        ))
        // We fetch one element over the page limit to then detect whether there is a next page.
        .limit(pagination.per_page as i64 + 1);

    // Load and paginate the results.
    let mut raw_invitations: Vec<CrateOwnerInvitation> = match pagination.page {
        Page::Unspecified => query.load(&*conn)?,
        Page::Seek(s) => {
            let seek_key: (i32, i32) = s.decode()?;
            query
                .filter(
                    crate_owner_invitations::crate_id.gt(seek_key.0).or(
                        crate_owner_invitations::crate_id
                            .eq(seek_key.0)
                            .and(crate_owner_invitations::invited_user_id.gt(seek_key.1)),
                    ),
                )
                .load(&*conn)?
        }
        Page::Numeric(_) => unreachable!("page-based pagination is disabled"),
    };
    let next_page = if raw_invitations.len() > pagination.per_page as usize {
        // We fetch `per_page + 1` to check if there are records for the next page. Since the last
        // element is not what the user wanted it's discarded.
        raw_invitations.pop();

        if let Some(last) = raw_invitations.last() {
            let mut params = IndexMap::new();
            params.insert(
                "seek".into(),
                crate::controllers::helpers::pagination::encode_seek((
                    last.crate_id,
                    last.invited_user_id,
                ))?,
            );
            Some(req.query_with_params(params))
        } else {
            None
        }
    } else {
        None
    };

    // Load all the related crates.
    let missing_crate_names = raw_invitations
        .iter()
        .map(|i| i.crate_id)
        .filter(|id| !crate_names.contains_key(id))
        .collect::<Vec<_>>();
    if !missing_crate_names.is_empty() {
        let new_names: Vec<(i32, String)> = crates::table
            .select((crates::id, crates::name))
            .filter(crates::id.eq_any(missing_crate_names))
            .load(&*conn)?;
        for (id, name) in new_names.into_iter() {
            crate_names.insert(id, name);
        }
    }

    // Load all the related users.
    let missing_users = raw_invitations
        .iter()
        .flat_map(|invite| {
            std::iter::once(invite.invited_user_id)
                .chain(std::iter::once(invite.invited_by_user_id))
        })
        .filter(|id| !users.contains_key(id))
        .collect::<Vec<_>>();
    if !missing_users.is_empty() {
        let new_users: Vec<User> = users::table
            .filter(users::id.eq_any(missing_users))
            .load(&*conn)?;
        for user in new_users.into_iter() {
            users.insert(user.id, user);
        }
    }

    // Turn `CrateOwnerInvitation`s into `EncodablePrivateCrateOwnerInvitation`.
    let config = &req.app().config;
    let mut invitations = Vec::new();
    let mut users_in_response = HashSet::new();
    for invitation in raw_invitations.into_iter() {
        invitations.push(EncodableCrateOwnerInvitation {
            invitee_id: invitation.invited_user_id,
            inviter_id: invitation.invited_by_user_id,
            crate_id: invitation.crate_id,
            crate_name: crate_names
                .get(&invitation.crate_id)
                .ok_or_else(|| internal(&format!("missing crate with id {}", invitation.crate_id)))?
                .clone(),
            created_at: invitation.created_at,
            expires_at: invitation.expires_at(config),
        });
        users_in_response.insert(invitation.invited_user_id);
        users_in_response.insert(invitation.invited_by_user_id);
    }

    // Provide a stable response for the users list, only including the referenced users with
    // stable sorting.
    users.retain(|k, _| users_in_response.contains(k));
    users.sort_keys();

    Ok(PrivateListResponse {
        invitations,
        users: users
            .into_iter()
            .map(|(_, user)| EncodablePublicUser::from(user))
            .collect(),
        meta: ResponseMeta { next_page },
    })
}

#[derive(Serialize)]
struct PrivateListResponse {
    invitations: Vec<EncodableCrateOwnerInvitation>,
    users: Vec<EncodablePublicUser>,
    meta: ResponseMeta,
}

#[derive(Serialize)]
struct ResponseMeta {
    next_page: Option<String>,
}

#[derive(Deserialize)]
struct OwnerInvitation {
    crate_owner_invite: InvitationResponse,
}

/// Handles the `PUT /api/v1/me/crate_owner_invitations/:crate_id` route.
pub fn handle_invite(req: &mut dyn RequestExt) -> EndpointResult {
    let mut body = String::new();
    req.body().read_to_string(&mut body)?;

    let crate_invite: OwnerInvitation =
        serde_json::from_str(&body).map_err(|_| bad_request("invalid json request"))?;

    let crate_invite = crate_invite.crate_owner_invite;
    let user_id = req.authenticate()?.user_id();
    let conn = &*req.db_conn()?;
    let config = &req.app().config;

    let invitation = CrateOwnerInvitation::find_by_id(user_id, crate_invite.crate_id, conn)?;
    if crate_invite.accepted {
        invitation.accept(conn, config)?;
    } else {
        invitation.decline(conn)?;
    }

    #[derive(Serialize)]
    struct R {
        crate_owner_invitation: InvitationResponse,
    }
    Ok(req.json(&R {
        crate_owner_invitation: crate_invite,
    }))
}

/// Handles the `PUT /api/v1/me/crate_owner_invitations/accept/:token` route.
pub fn handle_invite_with_token(req: &mut dyn RequestExt) -> EndpointResult {
    let config = &req.app().config;
    let conn = req.db_conn()?;
    let req_token = &req.params()["token"];

    let invitation = CrateOwnerInvitation::find_by_token(req_token, &conn)?;
    let crate_id = invitation.crate_id;
    invitation.accept(&conn, config)?;

    #[derive(Serialize)]
    struct R {
        crate_owner_invitation: InvitationResponse,
    }
    Ok(req.json(&R {
        crate_owner_invitation: InvitationResponse {
            crate_id,
            accepted: true,
        },
    }))
}
<commit_msg>Auto merge of #3850 - Turbo87:into, r=pietroalbini<commit_after>use super::frontend_prelude::*;

use crate::controllers::helpers::pagination::{Page, PaginationOptions};
use crate::controllers::util::AuthenticatedUser;
use crate::models::{Crate, CrateOwnerInvitation, Rights, User};
use crate::schema::{crate_owner_invitations, crates, users};
use crate::util::errors::{forbidden, internal};
use crate::views::{
    EncodableCrateOwnerInvitation, EncodableCrateOwnerInvitationV1, EncodablePublicUser,
    InvitationResponse,
};
use chrono::{Duration, Utc};
use diesel::{pg::Pg, sql_types::Bool};
use indexmap::IndexMap;
use std::collections::{HashMap, HashSet};

/// Handles the `GET /api/v1/me/crate_owner_invitations` route.
pub fn list(req: &mut dyn RequestExt) -> EndpointResult {
    let auth = req.authenticate()?.forbid_api_token_auth()?;
    let user_id = auth.user_id();

    let PrivateListResponse {
        invitations, users, ..
    } = prepare_list(req, auth, ListFilter::InviteeId(user_id))?;

    // The schema for the private endpoints is converted to the schema used by v1 endpoints.
    let crate_owner_invitations = invitations
        .into_iter()
        .map(|private| {
            Ok(EncodableCrateOwnerInvitationV1 {
                invited_by_username: users
                    .iter()
                    .find(|u| u.id == private.inviter_id)
                    .ok_or_else(|| internal(&format!("missing user {}", private.inviter_id)))?
                    .login
                    .clone(),
                invitee_id: private.invitee_id,
                inviter_id: private.inviter_id,
                crate_name: private.crate_name,
                crate_id: private.crate_id,
                created_at: private.created_at,
                expires_at: private.expires_at,
            })
        })
        .collect::<AppResult<Vec<EncodableCrateOwnerInvitationV1>>>()?;

    #[derive(Serialize)]
    struct R {
        crate_owner_invitations: Vec<EncodableCrateOwnerInvitationV1>,
        users: Vec<EncodablePublicUser>,
    }
    Ok(req.json(&R {
        crate_owner_invitations,
        users,
    }))
}

/// Handles the `GET /api/private/crate-owner-invitations` route.
pub fn private_list(req: &mut dyn RequestExt) -> EndpointResult {
    let auth = req.authenticate()?.forbid_api_token_auth()?;

    let filter = if let Some(crate_name) = req.query().get("crate_name") {
        ListFilter::CrateName(crate_name.clone())
    } else if let Some(id) = req.query().get("invitee_id").and_then(|i| i.parse().ok()) {
        ListFilter::InviteeId(id)
    } else {
        return Err(bad_request("missing or invalid filter"));
    };

    let list = prepare_list(req, auth, filter)?;
    Ok(req.json(&list))
}

enum ListFilter {
    CrateName(String),
    InviteeId(i32),
}

fn prepare_list(
    req: &mut dyn RequestExt,
    auth: AuthenticatedUser,
    filter: ListFilter,
) -> AppResult<PrivateListResponse> {
    let pagination: PaginationOptions = PaginationOptions::builder()
        .enable_pages(false)
        .enable_seek(true)
        .gather(req)?;

    let user = auth.user();
    let conn = req.db_read_only()?;
    let config = &req.app().config;

    let mut crate_names = HashMap::new();
    let mut users = IndexMap::new();
    users.insert(user.id, user.clone());

    let sql_filter: Box<dyn BoxableExpression<crate_owner_invitations::table, Pg, SqlType = Bool>> =
        match filter {
            ListFilter::CrateName(crate_name) => {
                // Only allow crate owners to query pending invitations for their crate.
                let krate: Crate = Crate::by_name(&crate_name).first(&*conn)?;
                let owners = krate.owners(&*conn)?;
                if user.rights(req.app(), &owners)? != Rights::Full {
                    return Err(forbidden());
                }

                // Cache the crate name to avoid querying it from the database again
                crate_names.insert(krate.id, krate.name.clone());

                Box::new(crate_owner_invitations::crate_id.eq(krate.id))
            }
            ListFilter::InviteeId(invitee_id) => {
                if invitee_id != user.id {
                    return Err(forbidden());
                }
                Box::new(crate_owner_invitations::invited_user_id.eq(invitee_id))
            }
        };

    // Load all the non-expired invitations matching the filter.
    let expire_cutoff = Duration::days(config.ownership_invitations_expiration_days as i64);
    let query = crate_owner_invitations::table
        .filter(sql_filter)
        .filter(crate_owner_invitations::created_at.gt((Utc::now() - expire_cutoff).naive_utc()))
        .order_by((
            crate_owner_invitations::crate_id,
            crate_owner_invitations::invited_user_id,
        ))
        // We fetch one element over the page limit to then detect whether there is a next page.
        .limit(pagination.per_page as i64 + 1);

    // Load and paginate the results.
    let mut raw_invitations: Vec<CrateOwnerInvitation> = match pagination.page {
        Page::Unspecified => query.load(&*conn)?,
        Page::Seek(s) => {
            let seek_key: (i32, i32) = s.decode()?;
            query
                .filter(
                    crate_owner_invitations::crate_id.gt(seek_key.0).or(
                        crate_owner_invitations::crate_id
                            .eq(seek_key.0)
                            .and(crate_owner_invitations::invited_user_id.gt(seek_key.1)),
                    ),
                )
                .load(&*conn)?
        }
        Page::Numeric(_) => unreachable!("page-based pagination is disabled"),
    };
    let next_page = if raw_invitations.len() > pagination.per_page as usize {
        // We fetch `per_page + 1` to check if there are records for the next page. Since the last
        // element is not what the user wanted it's discarded.
        raw_invitations.pop();

        if let Some(last) = raw_invitations.last() {
            let mut params = IndexMap::new();
            params.insert(
                "seek".into(),
                crate::controllers::helpers::pagination::encode_seek((
                    last.crate_id,
                    last.invited_user_id,
                ))?,
            );
            Some(req.query_with_params(params))
        } else {
            None
        }
    } else {
        None
    };

    // Load all the related crates.
    let missing_crate_names = raw_invitations
        .iter()
        .map(|i| i.crate_id)
        .filter(|id| !crate_names.contains_key(id))
        .collect::<Vec<_>>();
    if !missing_crate_names.is_empty() {
        let new_names: Vec<(i32, String)> = crates::table
            .select((crates::id, crates::name))
            .filter(crates::id.eq_any(missing_crate_names))
            .load(&*conn)?;
        for (id, name) in new_names.into_iter() {
            crate_names.insert(id, name);
        }
    }

    // Load all the related users.
    let missing_users = raw_invitations
        .iter()
        .flat_map(|invite| {
            std::iter::once(invite.invited_user_id)
                .chain(std::iter::once(invite.invited_by_user_id))
        })
        .filter(|id| !users.contains_key(id))
        .collect::<Vec<_>>();
    if !missing_users.is_empty() {
        let new_users: Vec<User> = users::table
            .filter(users::id.eq_any(missing_users))
            .load(&*conn)?;
        for user in new_users.into_iter() {
            users.insert(user.id, user);
        }
    }

    // Turn `CrateOwnerInvitation`s into `EncodablePrivateCrateOwnerInvitation`.
    let config = &req.app().config;
    let mut invitations = Vec::new();
    let mut users_in_response = HashSet::new();
    for invitation in raw_invitations.into_iter() {
        invitations.push(EncodableCrateOwnerInvitation {
            invitee_id: invitation.invited_user_id,
            inviter_id: invitation.invited_by_user_id,
            crate_id: invitation.crate_id,
            crate_name: crate_names
                .get(&invitation.crate_id)
                .ok_or_else(|| internal(&format!("missing crate with id {}", invitation.crate_id)))?
                .clone(),
            created_at: invitation.created_at,
            expires_at: invitation.expires_at(config),
        });
        users_in_response.insert(invitation.invited_user_id);
        users_in_response.insert(invitation.invited_by_user_id);
    }

    // Provide a stable response for the users list, only including the referenced users with
    // stable sorting.
    users.retain(|k, _| users_in_response.contains(k));
    users.sort_keys();

    Ok(PrivateListResponse {
        invitations,
        users: users.into_iter().map(|(_, user)| user.into()).collect(),
        meta: ResponseMeta { next_page },
    })
}

#[derive(Serialize)]
struct PrivateListResponse {
    invitations: Vec<EncodableCrateOwnerInvitation>,
    users: Vec<EncodablePublicUser>,
    meta: ResponseMeta,
}

#[derive(Serialize)]
struct ResponseMeta {
    next_page: Option<String>,
}

#[derive(Deserialize)]
struct OwnerInvitation {
    crate_owner_invite: InvitationResponse,
}

/// Handles the `PUT /api/v1/me/crate_owner_invitations/:crate_id` route.
pub fn handle_invite(req: &mut dyn RequestExt) -> EndpointResult {
    let mut body = String::new();
    req.body().read_to_string(&mut body)?;

    let crate_invite: OwnerInvitation =
        serde_json::from_str(&body).map_err(|_| bad_request("invalid json request"))?;

    let crate_invite = crate_invite.crate_owner_invite;
    let user_id = req.authenticate()?.user_id();
    let conn = &*req.db_conn()?;
    let config = &req.app().config;

    let invitation = CrateOwnerInvitation::find_by_id(user_id, crate_invite.crate_id, conn)?;
    if crate_invite.accepted {
        invitation.accept(conn, config)?;
    } else {
        invitation.decline(conn)?;
    }

    #[derive(Serialize)]
    struct R {
        crate_owner_invitation: InvitationResponse,
    }
    Ok(req.json(&R {
        crate_owner_invitation: crate_invite,
    }))
}

/// Handles the `PUT /api/v1/me/crate_owner_invitations/accept/:token` route.
pub fn handle_invite_with_token(req: &mut dyn RequestExt) -> EndpointResult {
    let config = &req.app().config;
    let conn = req.db_conn()?;
    let req_token = &req.params()["token"];

    let invitation = CrateOwnerInvitation::find_by_token(req_token, &conn)?;
    let crate_id = invitation.crate_id;
    invitation.accept(&conn, config)?;

    #[derive(Serialize)]
    struct R {
        crate_owner_invitation: InvitationResponse,
    }
    Ok(req.json(&R {
        crate_owner_invitation: InvitationResponse {
            crate_id,
            accepted: true,
        },
    }))
}
<|endoftext|>