<commit_before>//! Render combinatory blocks.
//!
//! Render blocks are logical rendering units that have inputs and outputs. Inputs can represent
//! vertex attributes, user-specified values, built-ins or previous blocks’ outputs.

use glsl::syntax::{ExternalDeclaration, Identifier, TranslationUnit, TypeName};
use glsl::visitor::{Host, Visit, Visitor};
use std::iter::once;

use crate::render::input::{Input, inputs_to_struct_decl};
use crate::render::output::{Output, outputs_to_struct_decl};

/// A render block, allowing for combining blocks in order to create more complex rendering
/// computations.
#[derive(Clone, Debug)]
struct Block {
  /// Unique identifier of the block. Used to get mangled names for structures and functions.
  id: String,
  /// List of inputs that compose the public interface of the block.
  inputs: Vec<Input>,
  /// List of outputs that compose the public interface of the block.
  outputs: Vec<Output>,
  /// Actual transformation code of the block.
  code: TranslationUnit
}

impl Block {
  /// Create a new block out of inputs, outputs and GLSL code.
  pub fn new<S, I, O, C>(id: S, inputs: I, outputs: O, code: C) -> Self
  where S: Into<String>,
        I: IntoIterator<Item = Input>,
        O: IntoIterator<Item = Output>,
        C: Into<TranslationUnit> {
    Block {
      id: id.into(),
      inputs: inputs.into_iter().collect(),
      outputs: outputs.into_iter().collect(),
      code: code.into()
    }
  }

  /// Turn a block into its GLSL header representation.
  ///
  /// The GLSL header contains the inputs and the outputs struct definitions.
  fn to_glsl_header(&self) -> Option<TranslationUnit> {
    // get the input and output GLSL representations
    let input_struct = inputs_to_struct_decl("In", &self.inputs);
    let output_struct = outputs_to_struct_decl("Out", &self.outputs);

    TranslationUnit::from_iter(once(input_struct).chain(once(output_struct)).flatten())
  }

  /// Turn a block into its GLSL full representation.
  ///
  /// The full GLSL representation includes:
  ///
  ///   - All intermediates structures, constants and functions.
  ///   - The *input* and *output* structures, renamed to:
  ///     - `In` becomes `In_<blockid>`. For instance, the block with ID `"Blur"` has its input type
  ///        going from `In` to `In_Blur`.
  ///     - `Out` becomes `Out_<blockid>`. For instance, the block with ID `"Blur"` has its output
  ///        type going from `Out` to `Out_Blur`.
  ///     - The function named `call` is searched for in the *code* part of the block and renamed
  ///       `call_<blockid>`. For instance, the block with ID `"Blur"` has its `call` function
  ///       renamed `call_Blur`.
  ///   - All references to `In`, `Out` and `call` are replaced with the appropriate new name.
  fn to_glsl(&self) -> Option<TranslationUnit> {
    // generate the header
    let mut ast = self.to_glsl_header()?;

    // append the actual code
    ast.extend((&self.code).into_iter().cloned());

    // transform the AST to mangle In, Out and call()
    let mut mangler = Mangler::new(self.id.as_str());
    ast.visit(&mut mangler);

    Some(ast)
  }
}

/// AST visitor that mangles type names and function calls.
///
/// This works but appending a unique ID to names to replace. Replacements occur for:
///
///   - All intermediates structures, constants and functions, that reference `In`, `Out` or `call`.
///   - The *input* and *output* structures, renamed as:
///     - `In` becomes `In_<blockid>`. For instance, the block with ID `"Blur"` has its input type
///        going from `In` to `In_Blur`.
///     - `Out` becomes `Out_<blockid>`. For instance, the block with ID `"Blur"` has its output
///        type going from `Out` to `Out_Blur`.
///     - The function named `call` is searched for in the *code* part of the block and renamed
///       `call_<blockid>`. For instance, the block with ID `"Blur"` has its `call` function
///       renamed `call_Blur`.
///   - All references to `In`, `Out` and `call` are replaced with the appropriate new name.
struct Mangler<'a> {
  id: &'a str
}

impl<'a> Mangler<'a> {
  fn new(id: &'a str) -> Self {
    Mangler { id }
  }
}

impl<'a> Visitor for Mangler<'a> {
  fn visit_type_name(&mut self, type_name: &mut TypeName) -> Visit {
    match type_name.as_str() {
      "In" => *type_name = TypeName::new(format!("In_{}", self.id)).unwrap(),
      "Out" => *type_name = TypeName::new(format!("Out_{}", self.id)).unwrap(),
      _ => ()
    }

    Visit::Parent
  }

  fn visit_identifier(&mut self, identifier: &mut Identifier) -> Visit {
    match identifier.as_str() {
      "In" => *identifier = Identifier::new(format!("In_{}", self.id)).unwrap(),
      "Out" => *identifier = Identifier::new(format!("Out_{}", self.id)).unwrap(),
      "call" => *identifier = Identifier::new(format!("call_{}", self.id)).unwrap(),
      _ => ()
    }

    Visit::Parent
  }
}

#[cfg(test)]
mod tests {
  use glsl_quasiquote::glsl;

  use crate::render::types::*;
  use super::*;

  #[test]
  fn block_to_glsl_header() {
    use crate::render::input::Input;
    use crate::render::output::Output;

    let inputs = vec![Input::new::<Float, _>("time"), Input::new::<RGBAU, _>("bias")];
    let outputs = vec![Output::new::<RGBF, _>("color")];
    let code = glsl!{ void main() {} };
    let block = Block::new("simple", inputs, outputs, code);
    let expected = glsl!{
      struct In {
        float time;
        uvec4 bias;
      };

      struct Out {
        vec3 color;
      };
    };

    assert_eq!(block.to_glsl_header(), Some(expected));
  }

  #[test]
  fn block_to_glsl() {
    use crate::render::input::Input;
    use crate::render::output::Output;

    let inputs = vec![Input::new::<Float, _>("time"), Input::new::<RGBAF, _>("bias")];
    let outputs = vec![Output::new::<RGBF, _>("color")];

    let code = glsl!{
      Out call(In x) {
        return Out(x.bias.xyz * x.time);
      }
    };

    let block = Block::new("simple", inputs, outputs, code);

    let expected = glsl!{
      struct In_simple {
        float time;
        vec4 bias;
      };

      struct Out_simple {
        vec3 color;
      };

      Out_simple call_simple(In_simple x) {
        return Out_simple(x.bias.xyz * x.time);
      }
    };

    assert_eq!(block.to_glsl(), Some(expected));
  }
}
<commit_msg>Remove some useless warnings.<commit_after>//! Render combinatory blocks.
//!
//! Render blocks are logical rendering units that have inputs and outputs. Inputs can represent
//! vertex attributes, user-specified values, built-ins or previous blocks’ outputs.

use glsl::syntax::{Identifier, TranslationUnit, TypeName};
use glsl::visitor::{Host, Visit, Visitor};
use std::iter::once;

use crate::render::input::{Input, inputs_to_struct_decl};
use crate::render::output::{Output, outputs_to_struct_decl};

/// A render block, allowing for combining blocks in order to create more complex rendering
/// computations.
#[derive(Clone, Debug)]
pub struct Block {
  /// Unique identifier of the block. Used to get mangled names for structures and functions.
  id: String,
  /// List of inputs that compose the public interface of the block.
  inputs: Vec<Input>,
  /// List of outputs that compose the public interface of the block.
  outputs: Vec<Output>,
  /// Actual transformation code of the block.
  code: TranslationUnit
}

impl Block {
  /// Create a new block out of inputs, outputs and GLSL code.
  pub fn new<S, I, O, C>(id: S, inputs: I, outputs: O, code: C) -> Self
  where S: Into<String>,
        I: IntoIterator<Item = Input>,
        O: IntoIterator<Item = Output>,
        C: Into<TranslationUnit> {
    Block {
      id: id.into(),
      inputs: inputs.into_iter().collect(),
      outputs: outputs.into_iter().collect(),
      code: code.into()
    }
  }

  /// Turn a block into its GLSL header representation.
  ///
  /// The GLSL header contains the inputs and the outputs struct definitions.
  fn to_glsl_header(&self) -> Option<TranslationUnit> {
    // get the input and output GLSL representations
    let input_struct = inputs_to_struct_decl("In", &self.inputs);
    let output_struct = outputs_to_struct_decl("Out", &self.outputs);

    TranslationUnit::from_iter(once(input_struct).chain(once(output_struct)).flatten())
  }

  /// Turn a block into its GLSL full representation.
  ///
  /// The full GLSL representation includes:
  ///
  ///   - All intermediates structures, constants and functions.
  ///   - The *input* and *output* structures, renamed to:
  ///     - `In` becomes `In_<blockid>`. For instance, the block with ID `"Blur"` has its input type
  ///        going from `In` to `In_Blur`.
  ///     - `Out` becomes `Out_<blockid>`. For instance, the block with ID `"Blur"` has its output
  ///        type going from `Out` to `Out_Blur`.
  ///     - The function named `call` is searched for in the *code* part of the block and renamed
  ///       `call_<blockid>`. For instance, the block with ID `"Blur"` has its `call` function
  ///       renamed `call_Blur`.
  ///   - All references to `In`, `Out` and `call` are replaced with the appropriate new name.
  fn to_glsl(&self) -> Option<TranslationUnit> {
    // generate the header
    let mut ast = self.to_glsl_header()?;

    // append the actual code
    ast.extend((&self.code).into_iter().cloned());

    // transform the AST to mangle In, Out and call()
    let mut mangler = Mangler::new(self.id.as_str());
    ast.visit(&mut mangler);

    Some(ast)
  }
}

/// AST visitor that mangles type names and function calls.
///
/// This works but appending a unique ID to names to replace. Replacements occur for:
///
///   - All intermediates structures, constants and functions, that reference `In`, `Out` or `call`.
///   - The *input* and *output* structures, renamed as:
///     - `In` becomes `In_<blockid>`. For instance, the block with ID `"Blur"` has its input type
///        going from `In` to `In_Blur`.
///     - `Out` becomes `Out_<blockid>`. For instance, the block with ID `"Blur"` has its output
///        type going from `Out` to `Out_Blur`.
///     - The function named `call` is searched for in the *code* part of the block and renamed
///       `call_<blockid>`. For instance, the block with ID `"Blur"` has its `call` function
///       renamed `call_Blur`.
///   - All references to `In`, `Out` and `call` are replaced with the appropriate new name.
struct Mangler<'a> {
  id: &'a str
}

impl<'a> Mangler<'a> {
  fn new(id: &'a str) -> Self {
    Mangler { id }
  }
}

impl<'a> Visitor for Mangler<'a> {
  fn visit_type_name(&mut self, type_name: &mut TypeName) -> Visit {
    match type_name.as_str() {
      "In" => *type_name = TypeName::new(format!("In_{}", self.id)).unwrap(),
      "Out" => *type_name = TypeName::new(format!("Out_{}", self.id)).unwrap(),
      _ => ()
    }

    Visit::Parent
  }

  fn visit_identifier(&mut self, identifier: &mut Identifier) -> Visit {
    match identifier.as_str() {
      "In" => *identifier = Identifier::new(format!("In_{}", self.id)).unwrap(),
      "Out" => *identifier = Identifier::new(format!("Out_{}", self.id)).unwrap(),
      "call" => *identifier = Identifier::new(format!("call_{}", self.id)).unwrap(),
      _ => ()
    }

    Visit::Parent
  }
}

#[cfg(test)]
mod tests {
  use glsl_quasiquote::glsl;

  use crate::render::types::*;
  use super::*;

  #[test]
  fn block_to_glsl_header() {
    use crate::render::input::Input;
    use crate::render::output::Output;

    let inputs = vec![Input::new::<Float, _>("time"), Input::new::<RGBAU, _>("bias")];
    let outputs = vec![Output::new::<RGBF, _>("color")];
    let code = glsl!{ void main() {} };
    let block = Block::new("simple", inputs, outputs, code);
    let expected = glsl!{
      struct In {
        float time;
        uvec4 bias;
      };

      struct Out {
        vec3 color;
      };
    };

    assert_eq!(block.to_glsl_header(), Some(expected));
  }

  #[test]
  fn block_to_glsl() {
    use crate::render::input::Input;
    use crate::render::output::Output;

    let inputs = vec![Input::new::<Float, _>("time"), Input::new::<RGBAF, _>("bias")];
    let outputs = vec![Output::new::<RGBF, _>("color")];

    let code = glsl!{
      Out call(In x) {
        return Out(x.bias.xyz * x.time);
      }
    };

    let block = Block::new("simple", inputs, outputs, code);

    let expected = glsl!{
      struct In_simple {
        float time;
        vec4 bias;
      };

      struct Out_simple {
        vec3 color;
      };

      Out_simple call_simple(In_simple x) {
        return Out_simple(x.bias.xyz * x.time);
      }
    };

    assert_eq!(block.to_glsl(), Some(expected));
  }
}
<|endoftext|>


<commit_before>// FIXME: Needs additional cocoa setup on OS X. rust-cocoa should probably just
// be a dependency

#[test]
#[ignore(cfg(target_os = "macos"))]
pub fn test_everything() {

    do task::spawn {
        assert sdl::init(~[sdl::InitVideo, sdl::InitTimer]) == true;
        run_tests(~[
            general::test_was_init,
            general::test_set_error,
            general::test_error,
            general::test_clear_error,
            video::test_set_video_mode,
            // FIXME: Doesn't work when called from a directory that
            // doesn't contain the test image file
            //video::test_blit, //Comment out before merge
            test_event::test_poll_event_none,
            // FIXME: This test is interactive
            //test_event::test_keyboard, //Comment out before merge

        ]);
        sdl::quit();
    }
}

fn run_tests(tests: &[fn()]) {
    for tests.each |test| {
        (*test)();
    }
}

mod general {
    pub fn test_was_init() {
        assert vec::contains(~[sdl::InitTimer], &sdl::InitTimer);
    }

    pub fn test_set_error() {
        sdl::set_error(~"test");
        assert sdl::get_error() == ~"test";
    }

    pub fn test_error() {
        sdl::clear_error();
        assert str::is_empty(sdl::get_error());
        sdl::error(sdl::ENoMem);
        assert str::is_not_empty(sdl::get_error());
    }

    pub fn test_clear_error() {
        sdl::set_error(~"test");
        sdl::clear_error();
        assert str::is_empty(sdl::get_error());
    }
}

mod test_event {
    pub fn test_poll_event_none() {
        ::event::poll_event(|event| assert event == ::event::NoEvent);
    }

    pub fn test_keyboard() {
        io::println(~"press a key in the window");
        let maybe_surface = ::video::set_video_mode(320, 200, 32,
            ~[::video::SWSurface], ~[::video::DoubleBuf, ::video::Resizable]);

        match maybe_surface {
            result::Ok(_) => {
                let mut keydown = false;
                let mut keyup = false;
                while !keydown || !keyup {
                    ::event::poll_event(|event| {
                        match event {
                          event::KeyUpEvent(keyboard) => {
                              keyup = true;
                              assert keyboard.keycode != keyboard::SDLKUnknown;
                          },
                          event::KeyDownEvent(keyboard) => {
                              keydown = true;
                              assert keyboard.keycode != keyboard::SDLKUnknown;
                          },
                          event::QuitEvent => fail,
                          _ => { }
                        }
                    })
                }
            }
            result::Err(_) => {
                fail;
            }
        }
    }
}

mod video {

    pub fn test_set_video_mode() {
        let maybe_surface = ::video::set_video_mode(320, 200, 32,
            ~[::video::HWSurface], ~[::video::DoubleBuf]);

        assert result::is_ok(&maybe_surface);
    }

    pub fn test_blit() {
        let maybe_screen = ::video::set_video_mode(320, 200, 32,
            ~[::video::SWSurface], ~[::video::DoubleBuf]);

        assert result::is_ok(&maybe_screen);

        match maybe_screen {
            result::Ok(screen) => {
                // FIXME: We need to load this from the crate instead of
                // off the filesystem
                let maybe_image = match ::video::load_bmp(~"rust-logo-128x128-blk.bmp") {
                    result::Ok(raw_image) => {
                        raw_image.display_format()
                    },
                    result::Err(err) => result::Err(err)
                };

                assert result::is_ok(&maybe_image);

                match maybe_image {
                    result::Ok(image) => {
                        for iter::repeat(1u) || {
                            screen.blit_surface(image);
                            screen.flip();
                            ::event::poll_event(|_event| {})
                        };
                    },
                    result::Err(_) => ()
                };
            },
            result::Err(_) => ()
        };
    }
}
<commit_msg>Reintroduced running tests on OSMain, as I took it out when I shouldn't have.<commit_after>// FIXME: Needs additional cocoa setup on OS X. rust-cocoa should probably just
// be a dependency

#[test]
#[ignore(cfg(target_os = "macos"))]
pub fn test_everything() {
    do on_osmain {
        assert sdl::init(~[sdl::InitVideo, sdl::InitTimer]) == true;
        run_tests(~[
            general::test_was_init,
            general::test_set_error,
            general::test_error,
            general::test_clear_error,
            video::test_set_video_mode,
            // FIXME: Doesn't work when called from a directory that
            // doesn't contain the test image file
            //video::test_blit,
            test_event::test_poll_event_none,
            // FIXME: This test is interactive
            //test_event::test_keyboard,

        ]);

        sdl::quit();
    }
}

fn on_osmain(f: ~fn()) {

    let (port, chan): (pipes::Port<()>, pipes::Chan<()>) = pipes::stream();

    do task::spawn_sched(task::PlatformThread) |move chan| {
        f();
        chan.send(());
    }
    port.recv();
}

fn run_tests(tests: &[fn()]) {
    for tests.each |test| {
        (*test)();
    }
}

mod general {
    pub fn test_was_init() {
        assert vec::contains(~[sdl::InitTimer], &sdl::InitTimer);
    }

    pub fn test_set_error() {
        sdl::set_error(~"test");
        assert sdl::get_error() == ~"test";
    }

    pub fn test_error() {
        sdl::clear_error();
        assert str::is_empty(sdl::get_error());
        sdl::error(sdl::ENoMem);
        assert str::is_not_empty(sdl::get_error());
    }

    pub fn test_clear_error() {
        sdl::set_error(~"test");
        sdl::clear_error();
        assert str::is_empty(sdl::get_error());
    }
}

mod test_event {
    pub fn test_poll_event_none() {
        ::event::poll_event(|event| assert event == ::event::NoEvent);
    }

    pub fn test_keyboard() {
        io::println(~"press a key in the window");
        let maybe_surface = ::video::set_video_mode(320, 200, 32,
            ~[::video::SWSurface], ~[::video::DoubleBuf, ::video::Resizable]);

        match maybe_surface {
            result::Ok(_) => {
                let mut keydown = false;
                let mut keyup = false;
                while !keydown || !keyup {
                    ::event::poll_event(|event| {
                        match event {
                          event::KeyUpEvent(keyboard) => {
                              keyup = true;
                              assert keyboard.keycode != keyboard::SDLKUnknown;
                          },
                          event::KeyDownEvent(keyboard) => {
                              keydown = true;
                              assert keyboard.keycode != keyboard::SDLKUnknown;
                          },
                          event::QuitEvent => fail,
                          _ => { }
                        }
                    })
                }
            }
            result::Err(_) => {
                fail;
            }
        }
    }
}

mod video {

    pub fn test_set_video_mode() {
        let maybe_surface = ::video::set_video_mode(320, 200, 32,
            ~[::video::HWSurface], ~[::video::DoubleBuf]);

        assert result::is_ok(&maybe_surface);
    }

    pub fn test_blit() {
        let maybe_screen = ::video::set_video_mode(320, 200, 32,
            ~[::video::SWSurface], ~[::video::DoubleBuf]);

        assert result::is_ok(&maybe_screen);

        match maybe_screen {
            result::Ok(screen) => {
                // FIXME: We need to load this from the crate instead of
                // off the filesystem
                let maybe_image = match ::video::load_bmp(~"rust-logo-128x128-blk.bmp") {
                    result::Ok(raw_image) => {
                        raw_image.display_format()
                    },
                    result::Err(err) => result::Err(err)
                };

                assert result::is_ok(&maybe_image);

                match maybe_image {
                    result::Ok(image) => {
                        for iter::repeat(1u) || {
                            screen.blit_surface(image);
                            screen.flip();
                            ::event::poll_event(|_event| {})
                        };
                    },
                    result::Err(_) => ()
                };
            },
            result::Err(_) => ()
        };
    }
}
<|endoftext|>


<commit_before>use std::{any::type_name, ops::Deref};

use actix_http::error::{Error, ErrorInternalServerError};
use futures_util::future;

use crate::{dev::Payload, FromRequest, HttpRequest};

/// Request-local data extractor.
///
/// Request-local data is arbitrary data attached to an individual request, usually
/// by middleware. It can be set via `extensions_mut` on [`HttpRequest`][htr_ext_mut]
/// or [`ServiceRequest`][srv_ext_mut].
///
/// Unlike app data, request data is dropped when the request has finished processing. This makes it
/// useful as a kind of messaging system between middleware and request handlers. It uses the same
/// types-as-keys storage system as app data.
///
/// # Mutating Request Data
/// Note that since extractors must output owned data, only types that `impl Clone` can use this
/// extractor. A clone is taken of the required request data and can, therefore, not be directly
/// mutated in-place. To mutate request data, continue to use [`HttpRequest::extensions_mut`] or
/// re-insert the cloned data back into the extensions map. A `DerefMut` impl is intentionally not
/// provided to make this potential foot-gun more obvious.
///
/// # Example
/// ```rust,no_run
/// # use actix_web::{web, HttpResponse, HttpRequest, Responder};
///
/// #[derive(Debug, Clone, PartialEq)]
/// struct FlagFromMiddleware(String);
///
/// /// Use the `ReqData<T>` extractor to access request data in a handler.
/// async fn handler(
///     req: HttpRequest,
///     opt_flag: Option<web::ReqData<FlagFromMiddleware>>,
/// ) -> impl Responder {
///     // use an optional extractor if the middleware is
///     // not guaranteed to add this type of requests data
///     if let Some(flag) = opt_flag {
///         assert_eq!(&flag.into_inner(), req.extensions().get::<FlagFromMiddleware>().unwrap());
///     }
///
///     HttpResponse::Ok()
/// }
/// ```
///
/// [htr_ext_mut]: crate::HttpRequest::extensions_mut
/// [srv_ext_mut]: crate::dev::ServiceRequest::extensions_mut
#[derive(Debug, Clone)]
pub struct ReqData<T: Clone + 'static>(T);

impl<T: Clone + 'static> ReqData<T> {
    /// Consumes the `ReqData`, returning it's wrapped data.
    pub fn into_inner(self) -> T {
        self.0
    }
}

impl<T: Clone + 'static> Deref for ReqData<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

impl<T: Clone + 'static> FromRequest for ReqData<T> {
    type Config = ();
    type Error = Error;
    type Future = future::Ready<Result<Self, Error>>;

    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        if let Some(st) = req.extensions().get::<T>() {
            future::ok(ReqData(st.clone()))
        } else {
            log::debug!(
                "Failed to construct App-level ReqData extractor. \
                 Request path: {:?} (type: {})",
                req.path(),
                type_name::<T>(),
            );
            future::err(ErrorInternalServerError(
                "Missing expected request extension data",
            ))
        }
    }
}

#[cfg(test)]
mod tests {
    use std::{cell::RefCell, rc::Rc};

    use futures_util::TryFutureExt as _;

    use super::*;
    use crate::{
        dev::Service,
        http::{Method, StatusCode},
        test::{init_service, TestRequest},
        web, App, HttpMessage, HttpResponse,
    };

    #[actix_rt::test]
    async fn req_data_extractor() {
        let mut srv = init_service(
            App::new()
                .wrap_fn(|req, srv| {
                    if req.method() == Method::POST {
                        req.extensions_mut().insert(42u32);
                    }

                    srv.call(req)
                })
                .service(web::resource("/test").to(
                    |req: HttpRequest, data: Option<ReqData<u32>>| {
                        if req.method() != Method::POST {
                            assert!(data.is_none());
                        }

                        if let Some(data) = data {
                            assert_eq!(*data, 42);
                            assert_eq!(
                                Some(data.into_inner()),
                                req.extensions().get::<u32>().copied()
                            );
                        }

                        HttpResponse::Ok()
                    },
                )),
        )
        .await;

        let req = TestRequest::get().uri("/test").to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        let req = TestRequest::post().uri("/test").to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);
    }

    #[actix_rt::test]
    async fn req_data_internal_mutability() {
        let mut srv = init_service(
            App::new()
                .wrap_fn(|req, srv| {
                    let data_before = Rc::new(RefCell::new(42u32));
                    req.extensions_mut().insert(data_before);

                    srv.call(req).map_ok(|res| {
                        {
                            let ext = res.request().extensions();
                            let data_after = ext.get::<Rc<RefCell<u32>>>().unwrap();
                            assert_eq!(*data_after.borrow(), 53u32);
                        }

                        res
                    })
                })
                .default_service(web::to(|data: ReqData<Rc<RefCell<u32>>>| {
                    assert_eq!(*data.borrow(), 42);
                    *data.borrow_mut() += 11;
                    assert_eq!(*data.borrow(), 53);

                    HttpResponse::Ok()
                })),
        )
        .await;

        let req = TestRequest::get().uri("/test").to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);
    }
}
<commit_msg>Fix typo in request_data.rs (#1774)<commit_after>use std::{any::type_name, ops::Deref};

use actix_http::error::{Error, ErrorInternalServerError};
use futures_util::future;

use crate::{dev::Payload, FromRequest, HttpRequest};

/// Request-local data extractor.
///
/// Request-local data is arbitrary data attached to an individual request, usually
/// by middleware. It can be set via `extensions_mut` on [`HttpRequest`][htr_ext_mut]
/// or [`ServiceRequest`][srv_ext_mut].
///
/// Unlike app data, request data is dropped when the request has finished processing. This makes it
/// useful as a kind of messaging system between middleware and request handlers. It uses the same
/// types-as-keys storage system as app data.
///
/// # Mutating Request Data
/// Note that since extractors must output owned data, only types that `impl Clone` can use this
/// extractor. A clone is taken of the required request data and can, therefore, not be directly
/// mutated in-place. To mutate request data, continue to use [`HttpRequest::extensions_mut`] or
/// re-insert the cloned data back into the extensions map. A `DerefMut` impl is intentionally not
/// provided to make this potential foot-gun more obvious.
///
/// # Example
/// ```rust,no_run
/// # use actix_web::{web, HttpResponse, HttpRequest, Responder};
///
/// #[derive(Debug, Clone, PartialEq)]
/// struct FlagFromMiddleware(String);
///
/// /// Use the `ReqData<T>` extractor to access request data in a handler.
/// async fn handler(
///     req: HttpRequest,
///     opt_flag: Option<web::ReqData<FlagFromMiddleware>>,
/// ) -> impl Responder {
///     // use an optional extractor if the middleware is
///     // not guaranteed to add this type of requests data
///     if let Some(flag) = opt_flag {
///         assert_eq!(&flag.into_inner(), req.extensions().get::<FlagFromMiddleware>().unwrap());
///     }
///
///     HttpResponse::Ok()
/// }
/// ```
///
/// [htr_ext_mut]: crate::HttpRequest::extensions_mut
/// [srv_ext_mut]: crate::dev::ServiceRequest::extensions_mut
#[derive(Debug, Clone)]
pub struct ReqData<T: Clone + 'static>(T);

impl<T: Clone + 'static> ReqData<T> {
    /// Consumes the `ReqData`, returning its wrapped data.
    pub fn into_inner(self) -> T {
        self.0
    }
}

impl<T: Clone + 'static> Deref for ReqData<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

impl<T: Clone + 'static> FromRequest for ReqData<T> {
    type Config = ();
    type Error = Error;
    type Future = future::Ready<Result<Self, Error>>;

    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        if let Some(st) = req.extensions().get::<T>() {
            future::ok(ReqData(st.clone()))
        } else {
            log::debug!(
                "Failed to construct App-level ReqData extractor. \
                 Request path: {:?} (type: {})",
                req.path(),
                type_name::<T>(),
            );
            future::err(ErrorInternalServerError(
                "Missing expected request extension data",
            ))
        }
    }
}

#[cfg(test)]
mod tests {
    use std::{cell::RefCell, rc::Rc};

    use futures_util::TryFutureExt as _;

    use super::*;
    use crate::{
        dev::Service,
        http::{Method, StatusCode},
        test::{init_service, TestRequest},
        web, App, HttpMessage, HttpResponse,
    };

    #[actix_rt::test]
    async fn req_data_extractor() {
        let mut srv = init_service(
            App::new()
                .wrap_fn(|req, srv| {
                    if req.method() == Method::POST {
                        req.extensions_mut().insert(42u32);
                    }

                    srv.call(req)
                })
                .service(web::resource("/test").to(
                    |req: HttpRequest, data: Option<ReqData<u32>>| {
                        if req.method() != Method::POST {
                            assert!(data.is_none());
                        }

                        if let Some(data) = data {
                            assert_eq!(*data, 42);
                            assert_eq!(
                                Some(data.into_inner()),
                                req.extensions().get::<u32>().copied()
                            );
                        }

                        HttpResponse::Ok()
                    },
                )),
        )
        .await;

        let req = TestRequest::get().uri("/test").to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        let req = TestRequest::post().uri("/test").to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);
    }

    #[actix_rt::test]
    async fn req_data_internal_mutability() {
        let mut srv = init_service(
            App::new()
                .wrap_fn(|req, srv| {
                    let data_before = Rc::new(RefCell::new(42u32));
                    req.extensions_mut().insert(data_before);

                    srv.call(req).map_ok(|res| {
                        {
                            let ext = res.request().extensions();
                            let data_after = ext.get::<Rc<RefCell<u32>>>().unwrap();
                            assert_eq!(*data_after.borrow(), 53u32);
                        }

                        res
                    })
                })
                .default_service(web::to(|data: ReqData<Rc<RefCell<u32>>>| {
                    assert_eq!(*data.borrow(), 42);
                    *data.borrow_mut() += 11;
                    assert_eq!(*data.borrow(), 53);

                    HttpResponse::Ok()
                })),
        )
        .await;

        let req = TestRequest::get().uri("/test").to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);
    }
}
<|endoftext|>


<commit_before>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>) // XXX: This is no value
}

trait Visitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool;
    fn pair(&mut self, key: ~str, val: Value) -> bool;
}

struct TOMLVisitor {
    root: HashMap<~str, Value>,
    current_section: ~str,
    section_is_array: bool
}

impl TOMLVisitor {
    fn new() -> TOMLVisitor {
        TOMLVisitor { root: HashMap::new(), current_section: ~"", section_is_array: false }
    }
    fn get_root<'a>(&'a self) -> &'a HashMap<~str, Value> {
        return &self.root;
    }
}

impl Visitor for TOMLVisitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool {
        debug!("Section: {} (is_array={})", name, is_array);
        self.section_is_array = is_array;
        self.current_section = name;
        return true
    }
    fn pair(&mut self, key: ~str, val: Value) -> bool {
        debug!("Pair: {} {:s}", key, val.to_str());
        let mut m = self.root.find_or_insert(self.current_section.clone(), Map(HashMap::new())); // XXX: remove clone
        match *m {
            Map(ref mut map) => {
                let ok = map.insert(key, val);
                return ok
            }
            _ => { return false }
        }
    }
}

fn read_char_opt(rd: &mut MemReader) -> Option<char> {
  match rd.read_byte() {
    Some(b) => Some(b as char),
    None => None
  }
}

struct Parser<'a> {
    rd: &'a mut MemReader,
    current_char: Option<char>
}

impl<'a> Parser<'a> {
    fn new(rd: &'a mut MemReader) -> Parser<'a> {
        let ch = read_char_opt(rd);
        Parser { rd: rd, current_char: ch }
    }

    fn advance(&mut self) {
        self.current_char = read_char_opt(self.rd);
    }

    fn ch(&self) -> Option<char> {
        return self.current_char;
    }

    fn eos(&self) -> bool {
        return self.current_char.is_none();
    }

    fn advance_if(&mut self, c: char) -> bool {
        match self.ch() {
            Some(ch) if ch == c => {
               self.advance();
               true
            }
            _ => {
                false
            }
        }
    }

    fn read_digit(&mut self) -> Option<u8> {
        let res = match self.ch() {
            Some('0') => Some(0),
            Some('1') => Some(1),
            Some('2') => Some(2),
            Some('3') => Some(3),
            Some('4') => Some(4),
            Some('5') => Some(5),
            Some('6') => Some(6),
            Some('7') => Some(7),
            Some('8') => Some(8),
            Some('9') => Some(9),
            _ => None
        };
        if res.is_some() { self.advance() }
        return res
    }

    fn read_digits(&mut self) -> Option<u64> {
        let mut num: u64;
        match self.read_digit() {
            Some(n) => { num = n as u64; }
            None => { return None }
        }
        loop {
            match self.read_digit() {
                Some(n) => {
                    // XXX: check range
                    num = num * 10 + (n as u64);
                }
                None => {
                    return Some(num)
                }
            }
        }
    }

    fn parse_value(&mut self) -> Option<Value> {
        self.skip_whitespaces();

        if self.eos() { return None }
        match self.ch().unwrap() {
            '-' => {
                // XXX: floating point
                self.advance();
                match self.read_digits() {
                    Some(n) => return Some(Integer(-(n as i64))), // XXX
                    None => return None
                }
            }
            '0' .. '9' => {
                // XXX: floating point + datetime
                match self.read_digits() {
                    Some(n) => return Some(Unsigned(n)),
                    None => return None
                }
            }
            't' => {
                self.advance();
                if self.advance_if('r') &&
                   self.advance_if('u') &&
                   self.advance_if('e') {
                    return Some(True)
                } else {
                    return None
                }
            }
            'f' => {
                self.advance();
                if self.advance_if('a') &&
                   self.advance_if('l') &&
                   self.advance_if('s') &&
                   self.advance_if('e') {
                    return Some(True)
                } else {
                    return None
                }
            }
            '[' => {
                self.advance();
                let mut arr = ~[];
                loop {
                    match self.parse_value() {
                        Some(val) => {
                            arr.push(val);
                        }
                        None => {
                            break;
                        }
                    }

                    self.skip_whitespaces_and_comments();
                    if !self.advance_if(',') { break }
                }
                self.skip_whitespaces_and_comments();
                if self.advance_if(']') {
                    return Some(Array(arr));
                } else {
                    return None;
                }
            }
            '"' => {
                self.advance();
                let str = self.read_token(|ch| {
                    match ch {
                        '"' => false,
                        _ => true
                    }
                });
                if self.advance_if('"') {
                    return Some(String(str))
                } else {
                    return None
                }
            }
            _ => { return None }
        }
    }

    fn read_token(&mut self, f: |char| -> bool) -> ~str {
        let mut token = ~"";
        loop {
            match self.ch() {
                Some(ch) => {
                    if f(ch) { token.push_char(ch) }
                    else { break }
                }
                None => { break }
            }
            self.advance();
        }

        return token;
    }

    fn parse_section_identifier(&mut self) -> ~str {
        self.read_token(|ch| {
            match ch {
                'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_' => true,
                _ => false
            }
        })
    }

    fn skip_whitespaces(&mut self) {
        loop {
            match self.ch() {
                Some(' ') | Some('\t') | Some('\r') | Some('\n') => {
                    self.advance();
                }
                _ => { break }
            }
        }
    }

    fn skip_whitespaces_and_comments(&mut self) {
        loop {
            match self.ch() {
                Some(' ') | Some('\t') | Some('\r') | Some('\n') => {
                    self.advance();
                }
                Some('#') => {
                    self.skip_comment();
                }
                _ => { break }
            }
        }
    }

    fn skip_comment(&mut self) {
        assert!(self.ch() == Some('#'));
        // skip to end of line
        loop {
            self.advance();
            match self.ch() {
                Some('\n') => { break }
                None => { return }
                _ => { /* skip */ }
            }
        }
        self.advance();
    }

    fn parse<V: Visitor>(&mut self, visitor: &mut V) -> bool {
        loop {
            if self.eos() { return true }
            match self.ch().unwrap() {
                // ignore whitespace
                '\r' | '\n' | ' ' | '\t' => {
                    self.advance();
                }

                // comment
                '#' => {
                    self.skip_comment();
                }

                // section
                '[' => {
                    self.advance();
                    let mut double_section = false;
                    match self.ch() {
                        Some('[') => {
                            double_section = true;
                            self.advance();
                        }
                        _ => {}
                    }

                    let section_name = self.parse_section_identifier();

                    if !self.advance_if(']') { return false }
                    if double_section {
                        if !self.advance_if(']') { return false }
                    }

                    visitor.section(section_name, double_section);
                }

                // identifier
                'a' .. 'z' | 'A' .. 'Z' | '_' => {

                    let ident = self.read_token(|ch| {
                        match ch {
                            'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' => true,
                            _ => false
                        }
                    });

                    self.skip_whitespaces();

                    if !self.advance_if('=') { return false } // assign wanted

                    match self.parse_value() {
                        Some(val) => { visitor.pair(ident, val); }
                        None => { return false; }
                    }
                    // do not advance!
                }

                _ => { return false }
            } /* end match */
        }

        assert!(false);
    }
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut visitor = TOMLVisitor::new();
  let mut rd = MemReader::new(contents);
  let mut parser = Parser::new(&mut rd);
  parser.parse(&mut visitor);
  println!("{:s}", visitor.get_root().to_str());
}
<commit_msg>Slight changes<commit_after>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>) // XXX: This is no value
}

trait Visitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool;
    fn pair(&mut self, key: ~str, val: Value) -> bool;
}

struct TOMLVisitor {
    root: HashMap<~str, Value>,
    current_section: ~str,
    section_is_array: bool
}

impl TOMLVisitor {
    fn new() -> TOMLVisitor {
        TOMLVisitor { root: HashMap::new(), current_section: ~"", section_is_array: false }
    }
    fn get_root<'a>(&'a self) -> &'a HashMap<~str, Value> {
        return &self.root;
    }
}

impl Visitor for TOMLVisitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool {
        debug!("Section: {} (is_array={})", name, is_array);
        self.section_is_array = is_array;
        self.current_section = name;
        return true
    }
    fn pair(&mut self, key: ~str, val: Value) -> bool {
        debug!("Pair: {} {:s}", key, val.to_str());
        let m = self.root.find_or_insert(self.current_section.clone(), Map(HashMap::new())); // XXX: remove clone
        match *m {
            Map(ref mut map) => {
                let ok = map.insert(key, val);
                return ok
            }
            _ => { return false }
        }
    }
}

struct Parser<'a> {
    rd: &'a mut MemReader,
    current_char: Option<char>
}

impl<'a> Parser<'a> {
    fn read_char(rd: &mut MemReader) -> Option<char> {
        match rd.read_byte() {
            Some(b) => Some(b as char),
            None => None
        }
    }

    fn new(rd: &'a mut MemReader) -> Parser<'a> {
        let ch = Parser::read_char(rd);
        Parser { rd: rd, current_char: ch }
    }

    fn advance(&mut self) {
        self.current_char = Parser::read_char(self.rd)
    }

    fn ch(&self) -> Option<char> {
        return self.current_char;
    }

    fn eos(&self) -> bool {
        return self.current_char.is_none();
    }

    fn advance_if(&mut self, c: char) -> bool {
        match self.ch() {
            Some(ch) if ch == c => {
               self.advance();
               true
            }
            _ => {
                false
            }
        }
    }

    fn read_digit(&mut self) -> Option<u8> {
        let res = match self.ch() {
            Some('0') => Some(0),
            Some('1') => Some(1),
            Some('2') => Some(2),
            Some('3') => Some(3),
            Some('4') => Some(4),
            Some('5') => Some(5),
            Some('6') => Some(6),
            Some('7') => Some(7),
            Some('8') => Some(8),
            Some('9') => Some(9),
            _ => None
        };
        if res.is_some() { self.advance() }
        return res
    }

    fn read_digits(&mut self) -> Option<u64> {
        let mut num: u64;
        match self.read_digit() {
            Some(n) => { num = n as u64; }
            None => { return None }
        }
        loop {
            match self.read_digit() {
                Some(n) => {
                    // XXX: check range
                    num = num * 10 + (n as u64);
                }
                None => {
                    return Some(num)
                }
            }
        }
    }

    fn parse_value(&mut self) -> Option<Value> {
        self.skip_whitespaces();

        if self.eos() { return None }
        match self.ch().unwrap() {
            '-' => {
                // XXX: floating point
                self.advance();
                match self.read_digits() {
                    Some(n) => return Some(Integer(-(n as i64))), // XXX
                    None => return None
                }
            }
            '0' .. '9' => {
                // XXX: floating point + datetime
                match self.read_digits() {
                    Some(n) => return Some(Unsigned(n)),
                    None => return None
                }
            }
            't' => {
                self.advance();
                if self.advance_if('r') &&
                   self.advance_if('u') &&
                   self.advance_if('e') {
                    return Some(True)
                } else {
                    return None
                }
            }
            'f' => {
                self.advance();
                if self.advance_if('a') &&
                   self.advance_if('l') &&
                   self.advance_if('s') &&
                   self.advance_if('e') {
                    return Some(True)
                } else {
                    return None
                }
            }
            '[' => {
                self.advance();
                let mut arr = ~[];
                loop {
                    match self.parse_value() {
                        Some(val) => {
                            arr.push(val);
                        }
                        None => {
                            break;
                        }
                    }

                    self.skip_whitespaces_and_comments();
                    if !self.advance_if(',') { break }
                }
                self.skip_whitespaces_and_comments();
                if self.advance_if(']') {
                    return Some(Array(arr));
                } else {
                    return None;
                }
            }
            '"' => {
                self.advance();
                let str = self.read_token(|ch| {
                    match ch {
                        '"' => false,
                        _ => true
                    }
                });
                if self.advance_if('"') {
                    return Some(String(str))
                } else {
                    return None
                }
            }
            _ => { return None }
        }
    }

    fn read_token(&mut self, f: |char| -> bool) -> ~str {
        let mut token = ~"";
        loop {
            match self.ch() {
                Some(ch) => {
                    if f(ch) { token.push_char(ch) }
                    else { break }
                }
                None => { break }
            }
            self.advance();
        }

        return token;
    }

    fn parse_section_identifier(&mut self) -> ~str {
        self.read_token(|ch| {
            match ch {
                'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_' => true,
                _ => false
            }
        })
    }

    fn skip_whitespaces(&mut self) {
        loop {
            match self.ch() {
                Some(' ') | Some('\t') | Some('\r') | Some('\n') => {
                    self.advance();
                }
                _ => { break }
            }
        }
    }

    fn skip_whitespaces_and_comments(&mut self) {
        loop {
            match self.ch() {
                Some(' ') | Some('\t') | Some('\r') | Some('\n') => {
                    self.advance();
                }
                Some('#') => {
                    self.skip_comment();
                }
                _ => { break }
            }
        }
    }

    fn skip_comment(&mut self) {
        assert!(self.ch() == Some('#'));
        // skip to end of line
        loop {
            self.advance();
            match self.ch() {
                Some('\n') => { break }
                None => { return }
                _ => { /* skip */ }
            }
        }
        self.advance();
    }

    fn parse<V: Visitor>(&mut self, visitor: &mut V) -> bool {
        loop {
            if self.eos() { return true }
            match self.ch().unwrap() {
                // ignore whitespace
                '\r' | '\n' | ' ' | '\t' => {
                    self.advance();
                }

                // comment
                '#' => {
                    self.skip_comment();
                }

                // section
                '[' => {
                    self.advance();
                    let mut double_section = false;
                    match self.ch() {
                        Some('[') => {
                            double_section = true;
                            self.advance();
                        }
                        _ => {}
                    }

                    let section_name = self.parse_section_identifier();

                    if !self.advance_if(']') { return false }
                    if double_section {
                        if !self.advance_if(']') { return false }
                    }

                    visitor.section(section_name, double_section);
                }

                // identifier
                'a' .. 'z' | 'A' .. 'Z' | '_' => {

                    let ident = self.read_token(|ch| {
                        match ch {
                            'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' => true,
                            _ => false
                        }
                    });

                    self.skip_whitespaces();

                    if !self.advance_if('=') { return false } // assign wanted

                    match self.parse_value() {
                        Some(val) => { visitor.pair(ident, val); }
                        None => { return false; }
                    }
                    // do not advance!
                }

                _ => { return false }
            } /* end match */
        }

        assert!(false);
    }
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut visitor = TOMLVisitor::new();
  let mut rd = MemReader::new(contents);
  let mut parser = Parser::new(&mut rd);
  parser.parse(&mut visitor);
  println!("{:s}", visitor.get_root().to_str());
}
<|endoftext|>


<commit_before>extern crate iron;

use iron::prelude::*;
use iron::status;

fn hck(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "")))
}

fn main() {
    Iron::new(|req: &mut Request| {
        println!("{:?}", req);
        println!("{}", req.version);
        println!("{:?}", req.headers);
        println!("{:?}", req.method);
        // println!("{}", req.body);
        Ok(Response::with((status::Ok, "Hello, world!")))
    }).http("localhost:3000").unwrap();
}

// NOTE: a "'static" lifetime means that this refence is used statically when borrowed
fn string_to_print() -> &'static str {
    "Hello, world!"
}

#[cfg(test)]
mod tests {
    // NOTE: bring into scope everything defined above
    use super::*;

    #[test]
    fn string_to_print_is_correct() {
        assert_eq!(string_to_print(), "Hello, world!");
    }
}
<commit_msg>Explicitly version the API<commit_after>extern crate iron;

use iron::prelude::*;
use iron::status;

struct Api(f32);

impl Api {
    fn version(&self) -> f32 {
        self.0
    }
}

fn main() {
    Iron::new(|req: &mut Request| {
        let api = Api (0.1);

        let hck = |_: &mut Request| -> IronResult<Response> {
            Ok(Response::with((status::Ok, format!("{}", api.version()))))
        };

        // NOTE: explicitly version the api
        let path = &req.url.path();
        let version = path[0];
        if version != api.version().to_string() {
            panic!("API version mismatch! This API version: {}", api.version());
        }

        println!("{:?}", path);
        println!("{:?}", req);
        println!("{}", req.version);
        println!("{:?}", req.headers);
        println!("{:?}", req.method);
        // println!("{}", req.body);
        Ok(Response::with((status::Ok, "Hello, world!")))
    }).http("localhost:3000").unwrap();
}

// NOTE: a "'static" lifetime means that this refence is used statically when borrowed
fn string_to_print() -> &'static str {
    "Hello, world!"
}

#[cfg(test)]
mod tests {
    // NOTE: bring into scope everything defined above
    use super::*;

    #[test]
    fn string_to_print_is_correct() {
        assert_eq!(string_to_print(), "Hello, world!");
    }
}
<|endoftext|>


<commit_before>extern crate bodyparser;
extern crate iron;
extern crate mount;
extern crate num;
extern crate plugin;
extern crate router;
extern crate rustc_serialize;
extern crate staticfile;

mod core;
mod error;
mod model;
mod server;

pub use error::MortgageError;
pub use model::{IntroductoryRate, Mortgage, MortgageStats, MortgageWithStats};

use iron::prelude::*;
use mount::Mount;
use router::Router;
use staticfile::Static;

use std::net::Ipv4Addr;

fn main() {
    let mut api = Router::new();
    api.post("/", server::create);

    let client = Static::new("client/");

    let mut mount = Mount::new();
    mount.mount("/", client);
    mount.mount("/mortgages", api);

    Iron::new(mount).http((Ipv4Addr::new(0, 0, 0, 0), 3000)).unwrap();
}
<commit_msg>Bind to localhost<commit_after>extern crate bodyparser;
extern crate iron;
extern crate mount;
extern crate num;
extern crate plugin;
extern crate router;
extern crate rustc_serialize;
extern crate staticfile;

mod core;
mod error;
mod model;
mod server;

pub use error::MortgageError;
pub use model::{IntroductoryRate, Mortgage, MortgageStats, MortgageWithStats};

use iron::prelude::*;
use mount::Mount;
use router::Router;
use staticfile::Static;

use std::net::Ipv4Addr;

fn main() {
    let mut api = Router::new();
    api.post("/", server::create);

    let client = Static::new("client/");

    let mut mount = Mount::new();
    mount.mount("/", client);
    mount.mount("/mortgages", api);

    Iron::new(mount).http((Ipv4Addr::new(127, 0, 0, 1), 3000)).unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fmt::{self, Debug};
use std::sync::{Condvar as StdCondvar, MutexGuard, WaitTimeoutResult};
use std::time::Duration;

static CONDVAR_POISONED: &str = "condvar is poisoned";

/// A Condition Variable.
#[derive(Default)]
pub struct Condvar {
    std: StdCondvar,
}

impl Condvar {
    /// Creates a new condvar that is ready to be waited on.
    pub fn new() -> Condvar {
        Condvar {
            std: StdCondvar::new(),
        }
    }

    /// Waits on a condvar, blocking the current thread until it is notified.
    pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
        self.std.wait(guard).expect(CONDVAR_POISONED)
    }

    /// Blocks the current thread until this condition variable receives a notification and the
    /// provided condition is false.
    pub fn wait_while<'a, T, F>(&self, guard: MutexGuard<'a, T>, condition: F) -> MutexGuard<'a, T>
    where
        F: FnMut(&mut T) -> bool,
    {
        self.std
            .wait_while(guard, condition)
            .expect(CONDVAR_POISONED)
    }

    /// Waits on a condvar, blocking the current thread until it is notified
    /// or the specified duration has elapsed.
    pub fn wait_timeout<'a, T>(
        &self,
        guard: MutexGuard<'a, T>,
        dur: Duration,
    ) -> (MutexGuard<'a, T>, WaitTimeoutResult) {
        self.std.wait_timeout(guard, dur).expect(CONDVAR_POISONED)
    }

    /// Waits on this condition variable for a notification, timing out after a specified duration.
    pub fn wait_timeout_while<'a, T, F>(
        &self,
        guard: MutexGuard<'a, T>,
        dur: Duration,
        condition: F,
    ) -> (MutexGuard<'a, T>, WaitTimeoutResult)
    where
        F: FnMut(&mut T) -> bool,
    {
        self.std
            .wait_timeout_while(guard, dur, condition)
            .expect(CONDVAR_POISONED)
    }

    /// Notifies one thread blocked by this condvar.
    pub fn notify_one(&self) {
        self.std.notify_one();
    }

    /// Notifies all threads blocked by this condvar.
    pub fn notify_all(&self) {
        self.std.notify_all();
    }
}

impl Debug for Condvar {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.std, formatter)
    }
}
<commit_msg>sync: Add wait_while variants to condvar wrapper<commit_after>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fmt::{self, Debug};
use std::sync::{Condvar as StdCondvar, MutexGuard, WaitTimeoutResult};
use std::time::Duration;

static CONDVAR_POISONED: &str = "condvar is poisoned";

/// A Condition Variable.
#[derive(Default)]
pub struct Condvar {
    std: StdCondvar,
}

impl Condvar {
    /// Creates a new condvar that is ready to be waited on.
    pub fn new() -> Condvar {
        Condvar {
            std: StdCondvar::new(),
        }
    }

    /// Waits on a condvar, blocking the current thread until it is notified.
    pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
        self.std.wait(guard).expect(CONDVAR_POISONED)
    }

    /// Blocks the current thread until this condition variable receives a notification and the
    /// provided condition is false.
    pub fn wait_while<'a, T, F>(&self, guard: MutexGuard<'a, T>, condition: F) -> MutexGuard<'a, T>
    where
        F: FnMut(&mut T) -> bool,
    {
        self.std
            .wait_while(guard, condition)
            .expect(CONDVAR_POISONED)
    }

    /// Waits on a condvar, blocking the current thread until it is notified
    /// or the specified duration has elapsed.
    pub fn wait_timeout<'a, T>(
        &self,
        guard: MutexGuard<'a, T>,
        dur: Duration,
    ) -> (MutexGuard<'a, T>, WaitTimeoutResult) {
        self.std.wait_timeout(guard, dur).expect(CONDVAR_POISONED)
    }

    /// Waits on this condition variable for a notification, timing out after a specified duration.
    pub fn wait_timeout_while<'a, T, F>(
        &self,
        guard: MutexGuard<'a, T>,
        dur: Duration,
        condition: F,
    ) -> (MutexGuard<'a, T>, WaitTimeoutResult)
    where
        F: FnMut(&mut T) -> bool,
    {
        self.std
            .wait_timeout_while(guard, dur, condition)
            .expect(CONDVAR_POISONED)
    }

    /// Waits on a condvar, blocking the current thread until it is notified and
    /// the provided condition is false.
    pub fn wait_while<'a, T, F>(&self, guard: MutexGuard<'a, T>, condition: F) -> MutexGuard<'a, T>
    where
        F: FnMut(&mut T) -> bool,
    {
        match self.std.wait_while(guard, condition) {
            Ok(result) => result,
            Err(_) => panic!("condvar is poisoned"),
        }
    }

    /// Waits on a condvar, blocking the current thread until it is notified and
    /// the provided condition is false, or until the specified duration has elapsed.
    pub fn wait_timeout_while<'a, T, F>(
        &self,
        guard: MutexGuard<'a, T>,
        dur: Duration,
        condition: F,
    ) -> (MutexGuard<'a, T>, WaitTimeoutResult)
    where
        F: FnMut(&mut T) -> bool,
    {
        match self.std.wait_timeout_while(guard, dur, condition) {
            Ok(result) => result,
            Err(_) => panic!("condvar is poisoned"),
        }
    }

    /// Notifies one thread blocked by this condvar.
    pub fn notify_one(&self) {
        self.std.notify_one();
    }

    /// Notifies all threads blocked by this condvar.
    pub fn notify_all(&self) {
        self.std.notify_all();
    }
}

impl Debug for Condvar {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.std, formatter)
    }
}
<|endoftext|>


<commit_before>use iced::{canvas, mouse, Canvas, Color, Element, Length, Point, Rectangle, Sandbox, Settings, Vector};
use oppai_field::field::{self, Field, Pos};
use oppai_field::player::Player;
use oppai_field::zobrist::Zobrist;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;

const SEED: [u8; 16] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53];

const FIELD_WIDTH: u32 = 39;
const FIELD_HEIGHT: u32 = 32;

pub fn main() {
  Game::run(Settings {
    antialiasing: true,
    ..Settings::default()
  });
}

struct Game {
  player: Player,
  field: Field,
  captures: Vec<(Vec<Pos>, Player)>,
}

#[derive(Debug, Clone, Copy)]
enum Message {
  PutPoint(Pos),
}

impl Sandbox for Game {
  type Message = Message;

  fn new() -> Self {
    let mut rng = XorShiftRng::from_seed(SEED);
    let zobrist = Zobrist::new(field::length(FIELD_WIDTH, FIELD_HEIGHT) * 2, &mut rng);
    let field = Field::new(FIELD_WIDTH, FIELD_HEIGHT, std::sync::Arc::new(zobrist));
    Game {
      player: Player::Red,
      field,
      captures: Vec::new(),
    }
  }

  fn title(&self) -> String {
    "OpPAI".into()
  }

  fn update(&mut self, message: Self::Message) {
    let Message::PutPoint(pos) = message;
    if self.field.put_point(pos, self.player) {
      self.player = self.player.next();
      let last_chain = self.field.get_last_chain();
      if let Some(&pos) = last_chain.first() {
        let player = self.field.cell(pos).get_player();
        self.captures.push((last_chain, player));
      }
    }
  }

  fn view(&mut self) -> iced::Element<'_, Self::Message> {
    let canvas = Canvas::new(self).height(Length::Fill).width(Length::Fill);
    Element::<Pos>::from(canvas).map(Message::PutPoint)
  }
}

impl canvas::Program<Pos> for Game {
  fn update(&mut self, event: canvas::Event, bounds: Rectangle, cursor: canvas::Cursor) -> Option<Pos> {
    let cursor_position = cursor.position_in(&bounds)?;
    let canvas::Event::Mouse(mouse_event) = event;
    match mouse_event {
      mouse::Event::ButtonPressed(mouse::Button::Left) => {
        let field_width = self.field.width();
        let field_height = self.field.height();
        let width = bounds
          .width
          .min(bounds.height / field_height as f32 * field_width as f32);
        let height = bounds
          .height
          .min(bounds.width / field_width as f32 * field_height as f32);
        let step_x = width / field_width as f32;
        let step_y = height / field_height as f32;
        let shift = Vector::new(
          ((bounds.width - width) / 2.0).round() + step_x / 2.0,
          ((bounds.height - height) / 2.0).round() + step_y / 2.0,
        );

        let point = cursor_position - shift;
        if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
          let x = (point.x / step_x).round() as u32;
          let y = (point.y / step_y).round() as u32;
          Some(self.field.to_pos(x, y))
        } else {
          None
        }
      }
      _ => None,
    }
  }

  fn draw(&self, bounds: Rectangle, cursor: canvas::Cursor) -> Vec<canvas::Geometry> {
    let mut frame = canvas::Frame::new(bounds.size());

    let field_width = self.field.width();
    let field_height = self.field.height();
    let width = frame
      .width()
      .min(frame.height() / field_height as f32 * field_width as f32);
    let height = frame
      .height()
      .min(frame.width() / field_width as f32 * field_height as f32);
    let step_x = width / field_width as f32;
    let step_y = height / field_height as f32;
    let shift = Vector::new(
      ((frame.width() - width) / 2.0).round(),
      ((frame.height() - height) / 2.0).round(),
    );

    let grid = canvas::Path::new(|path| {
      for x in 0..field_width {
        let offset = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
        path.move_to(Point::new(offset, 0.0) + shift);
        path.line_to(Point::new(offset, height) + shift);
      }
      for y in 0..field_height {
        let offset = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
        path.move_to(Point::new(0.0, offset) + shift);
        path.line_to(Point::new(width, offset) + shift);
      }
    });

    frame.stroke(
      &grid,
      canvas::Stroke {
        width: 1.0,
        color: Color::BLACK,
        ..canvas::Stroke::default()
      },
    );

    fn color(player: Player) -> Color {
      match player {
        Player::Red => Color::from_rgb8(0xFF, 0x00, 0x00),
        Player::Black => Color::BLACK,
      }
    }

    let xy_to_point = |x: u32, y: u32| {
      let offset_x = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
      let offset_y = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
      Point::new(offset_x, offset_y) + shift
    };
    let pos_to_point = |pos: Pos| {
      let x = self.field.to_x(pos);
      let y = self.field.to_y(pos);
      xy_to_point(x, y)
    };

    for &player in &[Player::Red, Player::Black] {
      let points = canvas::Path::new(|path| {
        for &pos in self
          .field
          .points_seq()
          .iter()
          .filter(|&&pos| self.field.cell(pos).is_players_point(player))
        {
          path.circle(pos_to_point(pos), 5.0)
        }
      });

      frame.fill(&points, color(player));
    }

    for (chain, player) in &self.captures {
      let path = canvas::Path::new(|path| {
        path.move_to(pos_to_point(chain[0]));
        for &pos in chain.iter().skip(1) {
          path.line_to(pos_to_point(pos));
        }
      });

      let mut color = color(*player);
      color.a = 0.5;

      frame.fill(&path, color);
    }

    if let Some(&pos) = self.field.points_seq().last() {
      let last_point = canvas::Path::new(|path| path.circle(pos_to_point(pos), 8.0));

      let color = color(self.field.cell(pos).get_player());

      frame.stroke(
        &last_point,
        canvas::Stroke {
          width: 2.0,
          color,
          ..canvas::Stroke::default()
        },
      );
    }

    if let Some(point) = cursor.position().and_then(|c| {
      let point = c - shift - Vector::new(step_x / 2.0, step_y / 2.0);
      if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
        let x = (point.x / step_x).round() as u32;
        let y = (point.y / step_y).round() as u32;
        let pos = self.field.to_pos(x, y);
        if self.field.is_putting_allowed(pos) {
          Some(xy_to_point(x, y))
        } else {
          None
        }
      } else {
        None
      }
    }) {
      let cursor_point = canvas::Path::new(|path| path.circle(point, 5.0));

      let mut color = color(self.player);
      color.a = 0.5;

      frame.fill(&cursor_point, color);
    }

    vec![frame.into_geometry()]
  }
}
<commit_msg>Implement full fill.<commit_after>use iced::{canvas, mouse, Canvas, Color, Element, Length, Point, Rectangle, Sandbox, Settings, Vector};
use oppai_field::field::{self, Field, Pos};
use oppai_field::player::Player;
use oppai_field::zobrist::Zobrist;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;

const SEED: [u8; 16] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53];

const FIELD_WIDTH: u32 = 39;
const FIELD_HEIGHT: u32 = 32;

pub fn main() {
  Game::run(Settings {
    antialiasing: true,
    ..Settings::default()
  });
}

struct Game {
  player: Player,
  field: Field,
  captures: Vec<(Vec<Pos>, Player)>,
}

#[derive(Debug, Clone, Copy)]
enum Message {
  PutPoint(Pos),
}

impl Sandbox for Game {
  type Message = Message;

  fn new() -> Self {
    let mut rng = XorShiftRng::from_seed(SEED);
    let zobrist = Zobrist::new(field::length(FIELD_WIDTH, FIELD_HEIGHT) * 2, &mut rng);
    let field = Field::new(FIELD_WIDTH, FIELD_HEIGHT, std::sync::Arc::new(zobrist));
    Game {
      player: Player::Red,
      field,
      captures: Vec::new(),
    }
  }

  fn title(&self) -> String {
    "OpPAI".into()
  }

  fn update(&mut self, message: Self::Message) {
    let Message::PutPoint(pos) = message;
    if self.field.put_point(pos, self.player) {
      let last_chain = self.field.get_last_chain();
      if let Some(&pos) = last_chain.first() {
        let player = self.field.cell(pos).get_player();
        self.captures.push((last_chain, player));
      }

      let n = self.field.n(pos);
      let s = self.field.s(pos);
      let w = self.field.w(pos);
      let e = self.field.e(pos);
      let nw = self.field.nw(pos);
      let ne = self.field.ne(pos);
      let sw = self.field.sw(pos);
      let se = self.field.se(pos);

      let mut check = |pos1: Pos, pos2: Pos| {
        if self.field.cell(pos1).get_players_point() == Some(self.player)
          && self.field.cell(pos2).get_players_point() == Some(self.player)
        {
          self.captures.push((vec![pos, pos1, pos2], self.player));
          true
        } else {
          false
        }
      };

      let _ = !check(s, e) && (check(s, se) || check(e, se));
      let _ = !check(e, n) && (check(e, ne) || check(n, ne));
      let _ = !check(n, w) && (check(n, nw) || check(w, nw));
      let _ = !check(w, s) && (check(w, sw) || check(s, sw));

      self.player = self.player.next();
    }
  }

  fn view(&mut self) -> iced::Element<'_, Self::Message> {
    let canvas = Canvas::new(self).height(Length::Fill).width(Length::Fill);
    Element::<Pos>::from(canvas).map(Message::PutPoint)
  }
}

impl canvas::Program<Pos> for Game {
  fn update(&mut self, event: canvas::Event, bounds: Rectangle, cursor: canvas::Cursor) -> Option<Pos> {
    let cursor_position = cursor.position_in(&bounds)?;
    let canvas::Event::Mouse(mouse_event) = event;
    match mouse_event {
      mouse::Event::ButtonPressed(mouse::Button::Left) => {
        let field_width = self.field.width();
        let field_height = self.field.height();
        let width = bounds
          .width
          .min(bounds.height / field_height as f32 * field_width as f32);
        let height = bounds
          .height
          .min(bounds.width / field_width as f32 * field_height as f32);
        let step_x = width / field_width as f32;
        let step_y = height / field_height as f32;
        let shift = Vector::new(
          ((bounds.width - width) / 2.0).round() + step_x / 2.0,
          ((bounds.height - height) / 2.0).round() + step_y / 2.0,
        );

        let point = cursor_position - shift;
        if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
          let x = (point.x / step_x).round() as u32;
          let y = (point.y / step_y).round() as u32;
          Some(self.field.to_pos(x, y))
        } else {
          None
        }
      }
      _ => None,
    }
  }

  fn draw(&self, bounds: Rectangle, cursor: canvas::Cursor) -> Vec<canvas::Geometry> {
    let mut frame = canvas::Frame::new(bounds.size());

    let field_width = self.field.width();
    let field_height = self.field.height();
    let width = frame
      .width()
      .min(frame.height() / field_height as f32 * field_width as f32);
    let height = frame
      .height()
      .min(frame.width() / field_width as f32 * field_height as f32);
    let step_x = width / field_width as f32;
    let step_y = height / field_height as f32;
    let shift = Vector::new(
      ((frame.width() - width) / 2.0).round(),
      ((frame.height() - height) / 2.0).round(),
    );

    let grid = canvas::Path::new(|path| {
      for x in 0..field_width {
        let offset = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
        path.move_to(Point::new(offset, 0.0) + shift);
        path.line_to(Point::new(offset, height) + shift);
      }
      for y in 0..field_height {
        let offset = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
        path.move_to(Point::new(0.0, offset) + shift);
        path.line_to(Point::new(width, offset) + shift);
      }
    });

    frame.stroke(
      &grid,
      canvas::Stroke {
        width: 1.0,
        color: Color::BLACK,
        ..canvas::Stroke::default()
      },
    );

    fn color(player: Player) -> Color {
      match player {
        Player::Red => Color::from_rgb8(0xFF, 0x00, 0x00),
        Player::Black => Color::BLACK,
      }
    }

    let xy_to_point = |x: u32, y: u32| {
      let offset_x = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
      let offset_y = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
      Point::new(offset_x, offset_y) + shift
    };
    let pos_to_point = |pos: Pos| {
      let x = self.field.to_x(pos);
      let y = self.field.to_y(pos);
      xy_to_point(x, y)
    };

    for &player in &[Player::Red, Player::Black] {
      let points = canvas::Path::new(|path| {
        for &pos in self
          .field
          .points_seq()
          .iter()
          .filter(|&&pos| self.field.cell(pos).is_players_point(player))
        {
          path.circle(pos_to_point(pos), 5.0)
        }
      });

      frame.fill(&points, color(player));
    }

    for (chain, player) in &self.captures {
      let path = canvas::Path::new(|path| {
        path.move_to(pos_to_point(chain[0]));
        for &pos in chain.iter().skip(1) {
          path.line_to(pos_to_point(pos));
        }
      });

      let mut color = color(*player);
      color.a = 0.5;

      frame.fill(&path, color);
    }

    if let Some(&pos) = self.field.points_seq().last() {
      let last_point = canvas::Path::new(|path| path.circle(pos_to_point(pos), 8.0));

      let color = color(self.field.cell(pos).get_player());

      frame.stroke(
        &last_point,
        canvas::Stroke {
          width: 2.0,
          color,
          ..canvas::Stroke::default()
        },
      );
    }

    if let Some(point) = cursor.position().and_then(|c| {
      let point = c - shift - Vector::new(step_x / 2.0, step_y / 2.0);
      if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
        let x = (point.x / step_x).round() as u32;
        let y = (point.y / step_y).round() as u32;
        let pos = self.field.to_pos(x, y);
        if self.field.is_putting_allowed(pos) {
          Some(xy_to_point(x, y))
        } else {
          None
        }
      } else {
        None
      }
    }) {
      let cursor_point = canvas::Path::new(|path| path.circle(point, 5.0));

      let mut color = color(self.player);
      color.a = 0.5;

      frame.fill(&cursor_point, color);
    }

    vec![frame.into_geometry()]
  }
}
<|endoftext|>


<commit_before>//! Print the contents of font tables.
//!
//! This accepts command line arguments similar to what is present in ttx,
//! although it does not produce xml output.

use std::{collections::HashSet, str::FromStr};

use font_types::Tag;
use read_fonts::{traversal::SomeTable, FontData, FontRef, ReadError, TableProvider};

mod print;
mod query;

use print::PrettyPrinter;
use query::Query;

fn main() -> Result<(), Error> {
    let args = flags::Args::from_env().map_err(|e| Error(e.to_string()))?;
    let bytes = std::fs::read(&args.input).unwrap();
    let data = FontData::new(&bytes);
    let font = FontRef::new(data).unwrap();
    if args.list {
        list_tables(&font);
        return Ok(());
    }

    if let Some(query) = &args.query {
        return query::print_query(&font, query).map_err(Error);
    }

    let filter = TableFilter::from_args(&args)?;
    print_tables(&font, &filter);
    Ok(())
}

fn list_tables(font: &FontRef) {
    println!("Tag  Offset  Length  Checksum");
    println!("-------------------------------");

    let offset_pad = get_offset_width(font);

    for record in font.table_directory.table_records() {
        println!(
            "{0} 0x{1:02$X} {3:8} 0x{4:08X} ",
            record.tag(),
            record.offset().to_u32(),
            offset_pad,
            record.length(),
            record.checksum()
        );
    }
}

fn print_tables(font: &FontRef, filter: &TableFilter) {
    for tag in font
        .table_directory
        .table_records()
        .iter()
        .map(|rec| rec.tag())
        .filter(|tag| filter.should_print(*tag))
    {
        print_table(font, tag)
    }
}

fn get_offset_width(font: &FontRef) -> usize {
    // pick how much padding we use for offsets based on the max offset in directory
    let max_off = font
        .table_directory
        .table_records()
        .iter()
        .map(|rec| rec.offset().to_u32())
        .max()
        .unwrap_or_default();
    hex_width(max_off)
}

/// Return the number of hex digits required to represent a given number.
fn hex_width(val: u32) -> usize {
    match val {
        0..=0xffff => 4usize,
        0x10000..=0xffff_ff => 6,
        0x1000000.. => 8,
    }
}

/// Given a font and a tag, return the appropriate table as a [`dyn SomeTable`][SomeTable].
fn get_some_table<'a>(
    font: &FontRef<'a>,
    tag: Tag,
) -> Result<Box<dyn SomeTable<'a> + 'a>, ReadError> {
    match tag {
        read_fonts::tables::gpos::TAG => font.gpos().map(|x| Box::new(x) as _),
        read_fonts::tables::gsub::TAG => font.gsub().map(|x| Box::new(x) as _),
        read_fonts::tables::cmap::TAG => font.cmap().map(|x| Box::new(x) as _),
        read_fonts::tables::gdef::TAG => font.gdef().map(|x| Box::new(x) as _),
        read_fonts::tables::glyf::TAG => font.glyf().map(|x| Box::new(x) as _),
        read_fonts::tables::head::TAG => font.head().map(|x| Box::new(x) as _),
        read_fonts::tables::hhea::TAG => font.hhea().map(|x| Box::new(x) as _),
        read_fonts::tables::hmtx::TAG => font.hmtx().map(|x| Box::new(x) as _),
        read_fonts::tables::loca::TAG => font.loca(None).map(|x| Box::new(x) as _),
        read_fonts::tables::maxp::TAG => font.maxp().map(|x| Box::new(x) as _),
        read_fonts::tables::name::TAG => font.name().map(|x| Box::new(x) as _),
        read_fonts::tables::post::TAG => font.post().map(|x| Box::new(x) as _),
        read_fonts::tables::colr::TAG => font.colr().map(|x| Box::new(x) as _),
        _ => Err(ReadError::TableIsMissing(tag)),
    }
}

fn print_table(font: &FontRef, tag: Tag) {
    match get_some_table(font, tag) {
        Ok(table) => fancy_print_table(&table).unwrap(),
        Err(err) => println!("{tag}: Error '{err}'"),
    }
}

enum TableFilter {
    All,
    Include(HashSet<Tag>),
    Exclude(HashSet<Tag>),
}

impl TableFilter {
    fn from_args(args: &flags::Args) -> Result<Self, Error> {
        if args.tables.is_some() && args.exclude.is_some() {
            return Err(Error::new("pass only one of --tables and --exclude"));
        }
        if let Some(tags) = &args.tables {
            make_tag_set(tags).map(TableFilter::Include)
        } else if let Some(tags) = &args.exclude {
            make_tag_set(tags).map(TableFilter::Exclude)
        } else {
            Ok(TableFilter::All)
        }
    }

    fn should_print(&self, tag: Tag) -> bool {
        match self {
            TableFilter::All => true,
            TableFilter::Include(tags) => tags.contains(&tag),
            TableFilter::Exclude(tags) => !tags.contains(&tag),
        }
    }
}

fn make_tag_set(inp: &str) -> Result<HashSet<Tag>, Error> {
    inp.split(' ')
        .map(|raw| match Tag::from_str(raw) {
            Ok(tag) => Ok(tag),
            Err(e) => Err(Error(format!(
                "Invalid tag '{}': {e}",
                raw.escape_default()
            ))),
        })
        .collect()
}

#[derive(Debug, Clone)]
struct Error(String);

impl Error {
    fn new(t: impl std::fmt::Display) -> Self {
        Self(t.to_string())
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

impl std::error::Error for Error {}

fn fancy_print_table<'a>(table: &(dyn SomeTable<'a> + 'a)) -> std::io::Result<()> {
    let stdout = std::io::stdout();
    let mut locked = stdout.lock();
    let mut formatter = PrettyPrinter::new(&mut locked);
    formatter.print_root_table(table)
}

mod flags {
    use super::Query;
    use std::path::PathBuf;

    xflags::xflags! {
        /// Generate font table representations
        cmd args
            required input: PathBuf
            {
                optional -l, --list
                optional -q, --query query: Query
                optional -t, --tables include: String
                optional -x, --exclude exclude: String
            }

    }
}
<commit_msg>[otexplorer] Print msg if requested tables are missing<commit_after>//! Print the contents of font tables.
//!
//! This accepts command line arguments similar to what is present in ttx,
//! although it does not produce xml output.

use std::{collections::HashSet, str::FromStr};

use font_types::Tag;
use read_fonts::{traversal::SomeTable, FontData, FontRef, ReadError, TableProvider};

mod print;
mod query;

use print::PrettyPrinter;
use query::Query;

fn main() -> Result<(), Error> {
    let args = flags::Args::from_env().map_err(|e| Error(e.to_string()))?;
    let bytes = std::fs::read(&args.input).unwrap();
    let data = FontData::new(&bytes);
    let font = FontRef::new(data).unwrap();
    if args.list {
        list_tables(&font);
        return Ok(());
    }

    if let Some(query) = &args.query {
        return query::print_query(&font, query).map_err(Error);
    }

    let filter = TableFilter::from_args(&args)?;
    print_tables(&font, &filter);
    Ok(())
}

fn list_tables(font: &FontRef) {
    println!("Tag  Offset  Length  Checksum");
    println!("-------------------------------");

    let offset_pad = get_offset_width(font);

    for record in font.table_directory.table_records() {
        println!(
            "{0} 0x{1:02$X} {3:8} 0x{4:08X} ",
            record.tag(),
            record.offset().to_u32(),
            offset_pad,
            record.length(),
            record.checksum()
        );
    }
}

fn print_tables(font: &FontRef, filter: &TableFilter) {
    let mut printed = HashSet::new();
    for tag in font
        .table_directory
        .table_records()
        .iter()
        .map(|rec| rec.tag())
        .filter(|tag| filter.should_print(*tag))
    {
        printed.insert(tag);
        print_table(font, tag)
    }

    if let TableFilter::Include(to_print) = filter {
        for unprinted in to_print.difference(&printed) {
            println!("Table {unprinted} not found");
        }
    }
}

fn get_offset_width(font: &FontRef) -> usize {
    // pick how much padding we use for offsets based on the max offset in directory
    let max_off = font
        .table_directory
        .table_records()
        .iter()
        .map(|rec| rec.offset().to_u32())
        .max()
        .unwrap_or_default();
    hex_width(max_off)
}

/// Return the number of hex digits required to represent a given number.
fn hex_width(val: u32) -> usize {
    match val {
        0..=0xffff => 4usize,
        0x10000..=0xffff_ff => 6,
        0x1000000.. => 8,
    }
}

/// Given a font and a tag, return the appropriate table as a [`dyn SomeTable`][SomeTable].
fn get_some_table<'a>(
    font: &FontRef<'a>,
    tag: Tag,
) -> Result<Box<dyn SomeTable<'a> + 'a>, ReadError> {
    match tag {
        read_fonts::tables::gpos::TAG => font.gpos().map(|x| Box::new(x) as _),
        read_fonts::tables::gsub::TAG => font.gsub().map(|x| Box::new(x) as _),
        read_fonts::tables::cmap::TAG => font.cmap().map(|x| Box::new(x) as _),
        read_fonts::tables::gdef::TAG => font.gdef().map(|x| Box::new(x) as _),
        read_fonts::tables::glyf::TAG => font.glyf().map(|x| Box::new(x) as _),
        read_fonts::tables::head::TAG => font.head().map(|x| Box::new(x) as _),
        read_fonts::tables::hhea::TAG => font.hhea().map(|x| Box::new(x) as _),
        read_fonts::tables::hmtx::TAG => font.hmtx().map(|x| Box::new(x) as _),
        read_fonts::tables::loca::TAG => font.loca(None).map(|x| Box::new(x) as _),
        read_fonts::tables::maxp::TAG => font.maxp().map(|x| Box::new(x) as _),
        read_fonts::tables::name::TAG => font.name().map(|x| Box::new(x) as _),
        read_fonts::tables::post::TAG => font.post().map(|x| Box::new(x) as _),
        read_fonts::tables::colr::TAG => font.colr().map(|x| Box::new(x) as _),
        _ => Err(ReadError::TableIsMissing(tag)),
    }
}

fn print_table(font: &FontRef, tag: Tag) {
    match get_some_table(font, tag) {
        Ok(table) => fancy_print_table(&table).unwrap(),
        Err(err) => println!("{tag}: Error '{err}'"),
    }
}

enum TableFilter {
    All,
    Include(HashSet<Tag>),
    Exclude(HashSet<Tag>),
}

impl TableFilter {
    fn from_args(args: &flags::Args) -> Result<Self, Error> {
        if args.tables.is_some() && args.exclude.is_some() {
            return Err(Error::new("pass only one of --tables and --exclude"));
        }
        if let Some(tags) = &args.tables {
            make_tag_set(tags).map(TableFilter::Include)
        } else if let Some(tags) = &args.exclude {
            make_tag_set(tags).map(TableFilter::Exclude)
        } else {
            Ok(TableFilter::All)
        }
    }

    fn should_print(&self, tag: Tag) -> bool {
        match self {
            TableFilter::All => true,
            TableFilter::Include(tags) => tags.contains(&tag),
            TableFilter::Exclude(tags) => !tags.contains(&tag),
        }
    }
}

fn make_tag_set(inp: &str) -> Result<HashSet<Tag>, Error> {
    inp.split(' ')
        .map(|raw| match Tag::from_str(raw) {
            Ok(tag) => Ok(tag),
            Err(e) => Err(Error(format!(
                "Invalid tag '{}': {e}",
                raw.escape_default()
            ))),
        })
        .collect()
}

#[derive(Debug, Clone)]
struct Error(String);

impl Error {
    fn new(t: impl std::fmt::Display) -> Self {
        Self(t.to_string())
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

impl std::error::Error for Error {}

fn fancy_print_table<'a>(table: &(dyn SomeTable<'a> + 'a)) -> std::io::Result<()> {
    let stdout = std::io::stdout();
    let mut locked = stdout.lock();
    let mut formatter = PrettyPrinter::new(&mut locked);
    formatter.print_root_table(table)
}

mod flags {
    use super::Query;
    use std::path::PathBuf;

    xflags::xflags! {
        /// Generate font table representations
        cmd args
            required input: PathBuf
            {
                optional -l, --list
                optional -q, --query query: Query
                optional -t, --tables include: String
                optional -x, --exclude exclude: String
            }

    }
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types, non_snake_case)]

use libc::c_void;

#[cfg(target_env = "msvc")]
mod win {
    use curl_sys;
    use kernel32;
    use libc::{c_int, c_long, c_uchar, c_void};
    use std::ffi::{CStr, CString};
    use std::mem;
    use std::ptr;
    use schannel::cert_context::ValidUses;
    use schannel::cert_store::CertStore;
    use winapi;

    fn lookup(module: Option<&str>, symbol: &str) -> Option<*const ::std::os::raw::c_void> {
        let symbol = CString::new(symbol).unwrap();
        unsafe {
            let mut mod_buf: Vec<u16>;
            let mod_ptr: *mut u16 = if let Some(module) = module {
                mod_buf = module.encode_utf16().collect();
                mod_buf.push(0);
                mod_buf.as_mut_ptr()
            } else {
                ptr::null_mut()
            };

            let handle = kernel32::GetModuleHandleW(mod_ptr);
            let n = kernel32::GetProcAddress(handle, symbol.as_ptr());
            if n == ptr::null() {
                None
            } else {
                Some(n)
            }
        }
    }

    pub enum X509_STORE {}
    pub enum X509 {}
    pub enum SSL_CTX {}

    type d2i_X509_fn = unsafe extern "C" fn(
        a: *mut *mut X509,
        pp: *mut *const c_uchar,
        length: c_long,
    ) -> *mut X509;
    type X509_free_fn = unsafe extern "C" fn(x: *mut X509);
    type X509_STORE_add_cert_fn = unsafe extern "C" fn(store: *mut X509_STORE, x: *mut X509)
        -> c_int;
    type SSL_CTX_get_cert_store_fn = unsafe extern "C" fn(ctx: *const SSL_CTX)
        -> *mut X509_STORE;

    struct OpenSSL {
        d2i_X509: d2i_X509_fn,
        X509_free: X509_free_fn,
        X509_STORE_add_cert: X509_STORE_add_cert_fn,
        SSL_CTX_get_cert_store: SSL_CTX_get_cert_store_fn,
    }

    fn lookup_functions(crypto_module: Option<&str>, ssl_module: Option<&str>) -> Option<OpenSSL> {
        let d2i_X509 = lookup(crypto_module, "d2i_X509");
        let X509_free = lookup(crypto_module, "X509_free");
        let X509_STORE_add_cert = lookup(crypto_module, "X509_STORE_add_cert");
        let SSL_CTX_get_cert_store = lookup(ssl_module, "SSL_CTX_get_cert_store");

        if d2i_X509.is_some() && X509_free.is_some() && X509_STORE_add_cert.is_some() &&
            SSL_CTX_get_cert_store.is_some()
        {
            unsafe {
                Some(OpenSSL {
                    d2i_X509: mem::transmute(d2i_X509.unwrap()),
                    X509_free: mem::transmute(X509_free.unwrap()),
                    X509_STORE_add_cert: mem::transmute(X509_STORE_add_cert.unwrap()),
                    SSL_CTX_get_cert_store: mem::transmute(SSL_CTX_get_cert_store.unwrap()),
                })
            }
        } else {
            None
        }
    }

    pub fn add_certs_to_context(ssl_ctx: *mut c_void) {
        unsafe {
            let curl_ver = curl_sys::curl_version_info(curl_sys::CURLVERSION_NOW);
            let ssl_ver = CStr::from_ptr((*curl_ver).ssl_version).to_string_lossy();
            let openssl = if ssl_ver.starts_with("OpenSSL/1.1.0") {
                lookup_functions(Some("libcrypto"), Some("libssl"))
            } else if ssl_ver.starts_with("OpenSSL/1.0.2") {
                lookup_functions(Some("libeay32"), Some("ssleay32"))
            } else {
                return;
            };

            if openssl.is_none() {
                return;
            }
            let openssl = openssl.unwrap();

            let openssl_store = (openssl.SSL_CTX_get_cert_store)(ssl_ctx as *const SSL_CTX);

            let mut store = if let Ok(s) = CertStore::open_current_user("ROOT") {
                s
            } else {
                return;
            };

            for cert in store.certs() {
                let valid_uses = if let Ok(v) = cert.valid_uses() {
                    v
                } else {
                    continue;
                };

                // check the extended key usage for the "Server Authentication" OID
                let is_server_auth = match valid_uses {
                    ValidUses::All => true,
                    ValidUses::OIDs(ref oids) => {
                        oids.contains(&winapi::wincrypt::szOID_PKIX_KP_SERVER_AUTH.to_owned())
                    }
                };

                if !is_server_auth {
                    continue;
                }

                let der = cert.to_der();
                let x509 =
                    (openssl.d2i_X509)(ptr::null_mut(), &mut der.as_ptr(), der.len() as c_long);
                if !x509.is_null() {
                    (openssl.X509_STORE_add_cert)(openssl_store, x509);
                    (openssl.X509_free)(x509);
                }
            }
        }
    }
}

#[cfg(target_env = "msvc")]
pub fn add_certs_to_context(ssl_ctx: *mut c_void) {
    win::add_certs_to_context(ssl_ctx)
}

#[cfg(not(target_env = "msvc"))]
pub fn add_certs_to_context(_: *mut c_void) {}
<commit_msg>remove unnecessary use of Option<commit_after>#![allow(non_camel_case_types, non_snake_case)]

use libc::c_void;

#[cfg(target_env = "msvc")]
mod win {
    use curl_sys;
    use kernel32;
    use libc::{c_int, c_long, c_uchar, c_void};
    use std::ffi::{CStr, CString};
    use std::mem;
    use std::ptr;
    use schannel::cert_context::ValidUses;
    use schannel::cert_store::CertStore;
    use winapi;

    fn lookup(module: &str, symbol: &str) -> Option<*const ::std::os::raw::c_void> {
        unsafe {
            let symbol = CString::new(symbol).unwrap();
            let mut mod_buf: Vec<u16> = module.encode_utf16().collect();
            mod_buf.push(0);
            let handle = kernel32::GetModuleHandleW(mod_buf.as_mut_ptr());
            let n = kernel32::GetProcAddress(handle, symbol.as_ptr());
            if n == ptr::null() {
                None
            } else {
                Some(n)
            }
        }
    }

    pub enum X509_STORE {}
    pub enum X509 {}
    pub enum SSL_CTX {}

    type d2i_X509_fn = unsafe extern "C" fn(
        a: *mut *mut X509,
        pp: *mut *const c_uchar,
        length: c_long,
    ) -> *mut X509;
    type X509_free_fn = unsafe extern "C" fn(x: *mut X509);
    type X509_STORE_add_cert_fn = unsafe extern "C" fn(store: *mut X509_STORE, x: *mut X509)
        -> c_int;
    type SSL_CTX_get_cert_store_fn = unsafe extern "C" fn(ctx: *const SSL_CTX)
        -> *mut X509_STORE;

    struct OpenSSL {
        d2i_X509: d2i_X509_fn,
        X509_free: X509_free_fn,
        X509_STORE_add_cert: X509_STORE_add_cert_fn,
        SSL_CTX_get_cert_store: SSL_CTX_get_cert_store_fn,
    }

    fn lookup_functions(crypto_module: &str, ssl_module: &str) -> Option<OpenSSL> {
        let d2i_X509 = lookup(crypto_module, "d2i_X509");
        let X509_free = lookup(crypto_module, "X509_free");
        let X509_STORE_add_cert = lookup(crypto_module, "X509_STORE_add_cert");
        let SSL_CTX_get_cert_store = lookup(ssl_module, "SSL_CTX_get_cert_store");

        if d2i_X509.is_some() && X509_free.is_some() && X509_STORE_add_cert.is_some() &&
            SSL_CTX_get_cert_store.is_some()
        {
            unsafe {
                Some(OpenSSL {
                    d2i_X509: mem::transmute(d2i_X509.unwrap()),
                    X509_free: mem::transmute(X509_free.unwrap()),
                    X509_STORE_add_cert: mem::transmute(X509_STORE_add_cert.unwrap()),
                    SSL_CTX_get_cert_store: mem::transmute(SSL_CTX_get_cert_store.unwrap()),
                })
            }
        } else {
            None
        }
    }

    pub fn add_certs_to_context(ssl_ctx: *mut c_void) {
        unsafe {
            // check the runtime version of OpenSSL
            let curl_ver = curl_sys::curl_version_info(curl_sys::CURLVERSION_NOW);
            let ssl_ver = CStr::from_ptr((*curl_ver).ssl_version).to_string_lossy();
            let openssl = if ssl_ver.starts_with("OpenSSL/1.1.0") {
                lookup_functions("libcrypto", "libssl")
            } else if ssl_ver.starts_with("OpenSSL/1.0.2") {
                lookup_functions("libeay32", "ssleay32")
            } else {
                return;
            };

            if openssl.is_none() {
                return;
            }
            let openssl = openssl.unwrap();

            let openssl_store = (openssl.SSL_CTX_get_cert_store)(ssl_ctx as *const SSL_CTX);

            let mut store = if let Ok(s) = CertStore::open_current_user("ROOT") {
                s
            } else {
                return;
            };

            for cert in store.certs() {
                let valid_uses = if let Ok(v) = cert.valid_uses() {
                    v
                } else {
                    continue;
                };

                // check the extended key usage for the "Server Authentication" OID
                let is_server_auth = match valid_uses {
                    ValidUses::All => true,
                    ValidUses::OIDs(ref oids) => {
                        oids.contains(&winapi::wincrypt::szOID_PKIX_KP_SERVER_AUTH.to_owned())
                    }
                };

                if !is_server_auth {
                    continue;
                }

                let der = cert.to_der();
                let x509 =
                    (openssl.d2i_X509)(ptr::null_mut(), &mut der.as_ptr(), der.len() as c_long);
                if !x509.is_null() {
                    (openssl.X509_STORE_add_cert)(openssl_store, x509);
                    (openssl.X509_free)(x509);
                }
            }
        }
    }
}

#[cfg(target_env = "msvc")]
pub fn add_certs_to_context(ssl_ctx: *mut c_void) {
    win::add_certs_to_context(ssl_ctx)
}

#[cfg(not(target_env = "msvc"))]
pub fn add_certs_to_context(_: *mut c_void) {}
<|endoftext|>