<commit_before>use luminance::{Dim2, Equation, Factor, Framebuffer, Flat, Mode, Pipe, Pipeline, RenderCommand, ShadingCommand, Tess, TessRender, TessVertices, Uniform, Unit, Vertex, VertexFormat};
use std::cell::RefCell;

use compositing::{ColorMap, DepthMap, RenderLayer};
use resource::Res;
use scene::Scene;
use shader::Program;
use text::TextTexture;
use texture::{RGBA32F, Texture};

/// Vertex used in overlay’s objects. Position coordinates are in *window space*.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Vert {
  /// Position.
  pub pos: [f32; 3],
  /// Color.
  pub color: [f32; 4]
}

impl Vert {
  pub fn new(pos: [f32; 3], color: [f32; 4]) -> Self {
    Vert {
      pos: pos,
      color: color
    }
  }

  /// Convert the vertex’ position to *clip space*.
  ///
  /// > Note: the depth coordinate is not affected.
  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    let converted = converter.from_win_coord(self.pos[0], self.pos[1]);
    let pos_ = [converted[0], converted[1], self.pos[2]];

    Vert {
      pos: pos_,
      color: self.color
    }
  }
}

impl Vertex for Vert {
  fn vertex_format() -> VertexFormat {
    <([f32; 3], [f32; 4]) as Vertex>::vertex_format()
  }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Triangle(pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Quad(pub Vert, pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Disc {
  pub center: Vert,
  pub radius: f32
}

impl Disc {
  pub fn new(center: Vert, radius: f32) -> Self {
    Disc {
      center: center,
      radius: radius
    }
  }

  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    Disc {
      center: self.center.to_clip_space(converter),
      radius: self.radius * converter.rw
    }
  }
}

impl Vertex for Disc {
  fn vertex_format() -> VertexFormat {
    <(Vert, f32) as Vertex>::vertex_format()
  }
}

pub type Texture2D = Texture<Flat, Dim2, RGBA32F>;

#[derive(Copy, Clone)]
pub struct Text<'a> {
  text_texture: &'a TextTexture,
  left_lower: Vert
}

impl<'a> Text<'a> {
  pub fn new(text_texture: &'a TextTexture, left_lower: Vert) -> Self {
    Text {
      text_texture: text_texture,
      left_lower: left_lower
    }
  }
}

const DISC_SCREEN_RATIO: &'static Uniform<f32> = &Uniform::new(0);

const TEXT_SAMPLER: &'static Uniform<Unit> = &Uniform::new(0);
const TEXT_POS: &'static Uniform<[f32; 3]> = &Uniform::new(1);
const TEXT_SIZE: &'static Uniform<[f32; 2]> = &Uniform::new(2);
const TEXT_SCALE: &'static Uniform<f32> = &Uniform::new(3);
const TEXT_COLOR: &'static Uniform<[f32; 4]> = &Uniform::new(4);

pub struct Overlay {
  ratio: f32,
  tri_program: Res<Program>,
  tris: RefCell<Tess>,
  disc_program: Res<Program>,
  discs: RefCell<Tess>,
  text_program: Res<Program>,
  text_quad: Tess,
  unit_converter: UnitConverter,
}

impl Overlay {
  pub fn new(w: u32, h: u32, max_tris: usize, max_quads: usize, max_discs: usize, scene: &mut Scene) -> Self {
    let tri_program = scene.get("spectra/overlay/triangle.glsl", vec![]).unwrap();
    let tris = Tess::new(Mode::Triangle, TessVertices::Reserve::<Vert>(max_tris * 3 + max_quads * 4), None);

    let disc_program = scene.get("spectra/overlay/disc.glsl", vec![DISC_SCREEN_RATIO.sem("ratio")]).unwrap();
    let discs = Tess::new(Mode::Point, TessVertices::Reserve::<Disc>(max_discs), None);

    let text_program = scene.get("spectra/overlay/text.glsl", vec![
      TEXT_SAMPLER.sem("text_texture"),
      TEXT_POS.sem("pos"),
      TEXT_SIZE.sem("size"),
      TEXT_SCALE.sem("scale"),
      TEXT_COLOR.sem("color")
    ]).unwrap();

    let text_quad = Tess::attributeless(Mode::TriangleStrip, 4);

    Overlay {
      ratio: w as f32 / h as f32,
      tri_program: tri_program,
      tris: RefCell::new(tris),
      disc_program: disc_program,
      discs: RefCell::new(discs),
      text_program: text_program,
      text_quad: text_quad,
      unit_converter: UnitConverter::new(w, h)
    }
  }

  /// Dispatch render input primitives into GPU buffers.
  fn dispatch(&self, input: &RenderInput) -> (usize, usize) {
    let mut tris_ref = self.tris.borrow_mut();
    let mut tris = tris_ref.as_slice_mut().unwrap();
    let mut tri_i = 0;

    let mut discs_ref = self.discs.borrow_mut();
    let mut discs = discs_ref.as_slice_mut().unwrap();
    let mut disc_i = 0;

    for &Triangle(a, b, c) in input.triangles {
      let abc = [a, b, c];

      for &v in &abc {
        tris[tri_i] = v.to_clip_space(&self.unit_converter);
        tri_i += 1;
      }
    }

    for &Quad(a, b, c, d) in input.quads {
      let abcd = [a, b, c, c, b, d];

      for &v in &abcd {
        tris[tri_i] = v.to_clip_space(&self.unit_converter);
        tri_i += 1;
      }
    }

    for disc in input.discs {
      discs[disc_i] = disc.to_clip_space(&self.unit_converter);
      disc_i += 1;
    }

    (tri_i, disc_i)
  }

  pub fn render(&self, framebuffer: &Framebuffer<Flat, Dim2, ColorMap, DepthMap>, input: &RenderInput) {
    let (tri_vert_nb, disc_vert_nb) = self.dispatch(input);

    let tris_ref = self.tris.borrow();
    let tris = TessRender::one_sub(&tris_ref, tri_vert_nb);

    let discs_ref = self.discs.borrow();
    let discs = TessRender::one_sub(&discs_ref, disc_vert_nb);

    let text_quad = TessRender::one_whole(&self.text_quad);
    let text_quad_render = [Pipe::new(text_quad)];

    let tri_program = self.tri_program.borrow();
    let disc_program = self.disc_program.borrow();
    let text_program = self.text_program.borrow();

    // FIXME: no alloc?
    let text_uniforms: Vec<_> = input.texts.map(|(texts, text_scale)| texts.iter().map(|text| {
      let (tex_w, tex_h) = text.text_texture.size();

      [
        TEXT_SAMPLER.alter(Unit::new(0)),
        TEXT_POS.alter(text.left_lower.to_clip_space(&self.unit_converter).pos),
        TEXT_SIZE.alter(self.unit_converter.from_win_dim(tex_w as f32, tex_h as f32)),
        TEXT_SCALE.alter(text_scale),
        TEXT_COLOR.alter(text.left_lower.color),
      ]
    }).collect()).unwrap_or(Vec::new());

    let text_textures: Vec<_> = input.texts.map(|(texts, _)| texts.iter().map(|text| [&***text.text_texture]).collect()).unwrap_or(Vec::new());

    let text_nb = input.texts.map(|(texts, _)| texts.len()).unwrap_or(0);
    let text_render_cmds: Vec<_> = (0..text_nb).map(|i| {
        let blending = (Equation::Additive, Factor::One, Factor::SrcAlphaComplement);
        Pipe::empty()
          .uniforms(&text_uniforms[i])
          .textures(&text_textures[i])
          .unwrap(RenderCommand::new(Some(blending), true, &text_quad_render))
      }).collect();

    let disc_uniforms = [
      DISC_SCREEN_RATIO.alter(self.ratio)
    ];

    let tris = &[Pipe::new(tris)];
    let tris_render_cmds = &[Pipe::new(RenderCommand::new(None, true, tris))];
    let discs = &[Pipe::new(discs)];
    let discs_render_cmds = &[Pipe::new(RenderCommand::new(None, true, discs))];

    Pipeline::new(framebuffer, [0., 0., 0., 1.], &[], &[], &[
      Pipe::new(ShadingCommand::new(&tri_program, tris_render_cmds)),
      Pipe::empty().uniforms(&disc_uniforms).unwrap(ShadingCommand::new(&disc_program, discs_render_cmds)),
      Pipe::new(ShadingCommand::new(&text_program, &text_render_cmds))
    ]).run();
  }
}

#[derive(Clone)]
pub struct RenderInput<'a> {
  triangles: &'a [Triangle],
  quads: &'a [Quad],
  discs: &'a [Disc],
  texts: Option<(&'a [Text<'a>], f32)>
}

impl<'a> RenderInput<'a> {
  pub fn new() -> Self {
    RenderInput {
      triangles: &[],
      quads: &[],
      discs: &[],
      texts: None,
    }
  }

  pub fn triangles(self, triangles: &'a [Triangle]) -> Self {
    RenderInput {
      triangles: triangles,
      ..self
    }
  }

  pub fn quads(self, quads: &'a [Quad]) -> Self {
    RenderInput {
      quads: quads,
      ..self
    }
  }

  pub fn discs(self, discs: &'a [Disc]) -> Self {
    RenderInput {
      discs: discs,
      ..self
    }
  }

  pub fn texts(self, texts: &'a [Text<'a>], scale: f32) -> Self {
    RenderInput {
      texts: Some((texts, scale.max(0.))),
      ..self
    }
  }
}

/// A *unit converter* is used to position stuff in overlay in a universal and screen independent
/// way.
///
/// The idea is that you provide should handle *window space* coordinates only. This type will then
/// help compute normalized coordinates the renderer can understand.
///
/// For the record, *window space* coordinates are defined as below – given a viewport size of
/// *w × h*:
///
/// ^ y = h
/// |
/// |
/// |    x = w
/// O------>
///
/// The formula used to convert from *window space* to what we call *clip space* is:
///
/// > x' = 2x / w - 1
/// > y' = 2y / h - 1
#[derive(Copy, Clone, Debug, PartialEq)]
struct UnitConverter {
  rw: f32,
  rh: f32,
  twice_rw: f32,
  twice_rh: f32
}

impl UnitConverter {
  /// Build a unit converter by giving it the size of the viewport.
  pub fn new(w: u32, h: u32) -> Self {
    let rw = 1. / (w as f32);
    let rh = 1. / (h as f32);

    UnitConverter {
      rw: rw,
      rh: rh,
      twice_rw: 2. * rw,
      twice_rh: 2. * rh
    }
  }

  /// Convert from *window space* coordinates to clip space* ones.
  pub fn from_win_coord(&self, x: f32, y: f32) -> [f32; 2] {
    let x_ = x * self.twice_rw - 1.;
    let y_ = y * self.twice_rh - 1.;

    [x_.min(1.).max(-1.), y_.min(1.).max(-1.)]
  }

  /// Convert from *window space* dimensions to clip space* ones.
  pub fn from_win_dim(&self, w: f32, h: f32) -> [f32; 2] {
    let w_ = w * self.rw;
    let h_ = h * self.rh;

    [w_.min(1.).max(-1.), h_.min(1.).max(-1.)]
  }
}
<commit_msg>Removed a warning.<commit_after>use luminance::{Dim2, Equation, Factor, Framebuffer, Flat, Mode, Pipe, Pipeline, RenderCommand, ShadingCommand, Tess, TessRender, TessVertices, Uniform, Unit, Vertex, VertexFormat};
use std::cell::RefCell;

use compositing::{ColorMap, DepthMap};
use resource::Res;
use scene::Scene;
use shader::Program;
use text::TextTexture;
use texture::{RGBA32F, Texture};

/// Vertex used in overlay’s objects. Position coordinates are in *window space*.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Vert {
  /// Position.
  pub pos: [f32; 3],
  /// Color.
  pub color: [f32; 4]
}

impl Vert {
  pub fn new(pos: [f32; 3], color: [f32; 4]) -> Self {
    Vert {
      pos: pos,
      color: color
    }
  }

  /// Convert the vertex’ position to *clip space*.
  ///
  /// > Note: the depth coordinate is not affected.
  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    let converted = converter.from_win_coord(self.pos[0], self.pos[1]);
    let pos_ = [converted[0], converted[1], self.pos[2]];

    Vert {
      pos: pos_,
      color: self.color
    }
  }
}

impl Vertex for Vert {
  fn vertex_format() -> VertexFormat {
    <([f32; 3], [f32; 4]) as Vertex>::vertex_format()
  }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Triangle(pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Quad(pub Vert, pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Disc {
  pub center: Vert,
  pub radius: f32
}

impl Disc {
  pub fn new(center: Vert, radius: f32) -> Self {
    Disc {
      center: center,
      radius: radius
    }
  }

  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    Disc {
      center: self.center.to_clip_space(converter),
      radius: self.radius * converter.rw
    }
  }
}

impl Vertex for Disc {
  fn vertex_format() -> VertexFormat {
    <(Vert, f32) as Vertex>::vertex_format()
  }
}

pub type Texture2D = Texture<Flat, Dim2, RGBA32F>;

#[derive(Copy, Clone)]
pub struct Text<'a> {
  text_texture: &'a TextTexture,
  left_lower: Vert
}

impl<'a> Text<'a> {
  pub fn new(text_texture: &'a TextTexture, left_lower: Vert) -> Self {
    Text {
      text_texture: text_texture,
      left_lower: left_lower
    }
  }
}

const DISC_SCREEN_RATIO: &'static Uniform<f32> = &Uniform::new(0);

const TEXT_SAMPLER: &'static Uniform<Unit> = &Uniform::new(0);
const TEXT_POS: &'static Uniform<[f32; 3]> = &Uniform::new(1);
const TEXT_SIZE: &'static Uniform<[f32; 2]> = &Uniform::new(2);
const TEXT_SCALE: &'static Uniform<f32> = &Uniform::new(3);
const TEXT_COLOR: &'static Uniform<[f32; 4]> = &Uniform::new(4);

pub struct Overlay {
  ratio: f32,
  tri_program: Res<Program>,
  tris: RefCell<Tess>,
  disc_program: Res<Program>,
  discs: RefCell<Tess>,
  text_program: Res<Program>,
  text_quad: Tess,
  unit_converter: UnitConverter,
}

impl Overlay {
  pub fn new(w: u32, h: u32, max_tris: usize, max_quads: usize, max_discs: usize, scene: &mut Scene) -> Self {
    let tri_program = scene.get("spectra/overlay/triangle.glsl", vec![]).unwrap();
    let tris = Tess::new(Mode::Triangle, TessVertices::Reserve::<Vert>(max_tris * 3 + max_quads * 4), None);

    let disc_program = scene.get("spectra/overlay/disc.glsl", vec![DISC_SCREEN_RATIO.sem("ratio")]).unwrap();
    let discs = Tess::new(Mode::Point, TessVertices::Reserve::<Disc>(max_discs), None);

    let text_program = scene.get("spectra/overlay/text.glsl", vec![
      TEXT_SAMPLER.sem("text_texture"),
      TEXT_POS.sem("pos"),
      TEXT_SIZE.sem("size"),
      TEXT_SCALE.sem("scale"),
      TEXT_COLOR.sem("color")
    ]).unwrap();

    let text_quad = Tess::attributeless(Mode::TriangleStrip, 4);

    Overlay {
      ratio: w as f32 / h as f32,
      tri_program: tri_program,
      tris: RefCell::new(tris),
      disc_program: disc_program,
      discs: RefCell::new(discs),
      text_program: text_program,
      text_quad: text_quad,
      unit_converter: UnitConverter::new(w, h)
    }
  }

  /// Dispatch render input primitives into GPU buffers.
  fn dispatch(&self, input: &RenderInput) -> (usize, usize) {
    let mut tris_ref = self.tris.borrow_mut();
    let mut tris = tris_ref.as_slice_mut().unwrap();
    let mut tri_i = 0;

    let mut discs_ref = self.discs.borrow_mut();
    let mut discs = discs_ref.as_slice_mut().unwrap();
    let mut disc_i = 0;

    for &Triangle(a, b, c) in input.triangles {
      let abc = [a, b, c];

      for &v in &abc {
        tris[tri_i] = v.to_clip_space(&self.unit_converter);
        tri_i += 1;
      }
    }

    for &Quad(a, b, c, d) in input.quads {
      let abcd = [a, b, c, c, b, d];

      for &v in &abcd {
        tris[tri_i] = v.to_clip_space(&self.unit_converter);
        tri_i += 1;
      }
    }

    for disc in input.discs {
      discs[disc_i] = disc.to_clip_space(&self.unit_converter);
      disc_i += 1;
    }

    (tri_i, disc_i)
  }

  pub fn render(&self, framebuffer: &Framebuffer<Flat, Dim2, ColorMap, DepthMap>, input: &RenderInput) {
    let (tri_vert_nb, disc_vert_nb) = self.dispatch(input);

    let tris_ref = self.tris.borrow();
    let tris = TessRender::one_sub(&tris_ref, tri_vert_nb);

    let discs_ref = self.discs.borrow();
    let discs = TessRender::one_sub(&discs_ref, disc_vert_nb);

    let text_quad = TessRender::one_whole(&self.text_quad);
    let text_quad_render = [Pipe::new(text_quad)];

    let tri_program = self.tri_program.borrow();
    let disc_program = self.disc_program.borrow();
    let text_program = self.text_program.borrow();

    // FIXME: no alloc?
    let text_uniforms: Vec<_> = input.texts.map(|(texts, text_scale)| texts.iter().map(|text| {
      let (tex_w, tex_h) = text.text_texture.size();

      [
        TEXT_SAMPLER.alter(Unit::new(0)),
        TEXT_POS.alter(text.left_lower.to_clip_space(&self.unit_converter).pos),
        TEXT_SIZE.alter(self.unit_converter.from_win_dim(tex_w as f32, tex_h as f32)),
        TEXT_SCALE.alter(text_scale),
        TEXT_COLOR.alter(text.left_lower.color),
      ]
    }).collect()).unwrap_or(Vec::new());

    let text_textures: Vec<_> = input.texts.map(|(texts, _)| texts.iter().map(|text| [&***text.text_texture]).collect()).unwrap_or(Vec::new());

    let text_nb = input.texts.map(|(texts, _)| texts.len()).unwrap_or(0);
    let text_render_cmds: Vec<_> = (0..text_nb).map(|i| {
        let blending = (Equation::Additive, Factor::One, Factor::SrcAlphaComplement);
        Pipe::empty()
          .uniforms(&text_uniforms[i])
          .textures(&text_textures[i])
          .unwrap(RenderCommand::new(Some(blending), true, &text_quad_render))
      }).collect();

    let disc_uniforms = [
      DISC_SCREEN_RATIO.alter(self.ratio)
    ];

    let tris = &[Pipe::new(tris)];
    let tris_render_cmds = &[Pipe::new(RenderCommand::new(None, true, tris))];
    let discs = &[Pipe::new(discs)];
    let discs_render_cmds = &[Pipe::new(RenderCommand::new(None, true, discs))];

    Pipeline::new(framebuffer, [0., 0., 0., 1.], &[], &[], &[
      Pipe::new(ShadingCommand::new(&tri_program, tris_render_cmds)),
      Pipe::empty().uniforms(&disc_uniforms).unwrap(ShadingCommand::new(&disc_program, discs_render_cmds)),
      Pipe::new(ShadingCommand::new(&text_program, &text_render_cmds))
    ]).run();
  }
}

#[derive(Clone)]
pub struct RenderInput<'a> {
  triangles: &'a [Triangle],
  quads: &'a [Quad],
  discs: &'a [Disc],
  texts: Option<(&'a [Text<'a>], f32)>
}

impl<'a> RenderInput<'a> {
  pub fn new() -> Self {
    RenderInput {
      triangles: &[],
      quads: &[],
      discs: &[],
      texts: None,
    }
  }

  pub fn triangles(self, triangles: &'a [Triangle]) -> Self {
    RenderInput {
      triangles: triangles,
      ..self
    }
  }

  pub fn quads(self, quads: &'a [Quad]) -> Self {
    RenderInput {
      quads: quads,
      ..self
    }
  }

  pub fn discs(self, discs: &'a [Disc]) -> Self {
    RenderInput {
      discs: discs,
      ..self
    }
  }

  pub fn texts(self, texts: &'a [Text<'a>], scale: f32) -> Self {
    RenderInput {
      texts: Some((texts, scale.max(0.))),
      ..self
    }
  }
}

/// A *unit converter* is used to position stuff in overlay in a universal and screen independent
/// way.
///
/// The idea is that you provide should handle *window space* coordinates only. This type will then
/// help compute normalized coordinates the renderer can understand.
///
/// For the record, *window space* coordinates are defined as below – given a viewport size of
/// *w × h*:
///
/// ^ y = h
/// |
/// |
/// |    x = w
/// O------>
///
/// The formula used to convert from *window space* to what we call *clip space* is:
///
/// > x' = 2x / w - 1
/// > y' = 2y / h - 1
#[derive(Copy, Clone, Debug, PartialEq)]
struct UnitConverter {
  rw: f32,
  rh: f32,
  twice_rw: f32,
  twice_rh: f32
}

impl UnitConverter {
  /// Build a unit converter by giving it the size of the viewport.
  pub fn new(w: u32, h: u32) -> Self {
    let rw = 1. / (w as f32);
    let rh = 1. / (h as f32);

    UnitConverter {
      rw: rw,
      rh: rh,
      twice_rw: 2. * rw,
      twice_rh: 2. * rh
    }
  }

  /// Convert from *window space* coordinates to clip space* ones.
  pub fn from_win_coord(&self, x: f32, y: f32) -> [f32; 2] {
    let x_ = x * self.twice_rw - 1.;
    let y_ = y * self.twice_rh - 1.;

    [x_.min(1.).max(-1.), y_.min(1.).max(-1.)]
  }

  /// Convert from *window space* dimensions to clip space* ones.
  pub fn from_win_dim(&self, w: f32, h: f32) -> [f32; 2] {
    let w_ = w * self.rw;
    let h_ = h * self.rh;

    [w_.min(1.).max(-1.), h_.min(1.).max(-1.)]
  }
}
<|endoftext|>


<commit_before>use bson;
use client::wire_protocol::flags::OpQueryFlags;
use client::wire_protocol::operations::Message;
use std::collections::vec_deque::VecDeque;
use std::io::{Read, Write};

/// Maintains a connection to the server and lazily returns documents from a
/// query.
///
/// # Fields
///
/// `request_id` - Uniquely identifies the request being sent.
/// `namespace` - The full qualified name of the collection,
///                          beginning with the database name and a period.
/// `batch_size` - How many documents to fetch at a given time from the server.
/// `cursor_id` - Uniquely identifies the cursor being returned by the reply.
pub struct Cursor<'a, T> where T: Read + Write + 'a {
    request_id: i32,
    namespace: String,
    batch_size: i32,
    cursor_id: i64,
    limit: i32,
    count: i32,
    buffer: VecDeque<bson::Document>,
    stream: &'a mut T,
}

impl <'a, T> Cursor<'a, T> where T: Read + Write + 'a {
    /// Gets the cursor id and BSON documents from a reply Message.
    ///
    /// # Arguments
    ///
    /// `message` - The reply message to get the documents from.
    ///
    /// # Return value.
    ///
    ///
    fn get_bson_and_cid_from_message(message: Message) -> Option<(VecDeque<bson::Document>, i64)> {
        match message {
            Message::OpReply { header: _, flags: _, cursor_id: cid,
                               starting_from: _, number_returned: _,
                               documents: docs } => {
                let mut v = VecDeque::new();

                for doc in docs {
                    v.push_back(doc);
                }

                Some((v, cid))
            },
            _ => None
        }
    }

    pub fn query_with_batch_size(stream: &'a mut T, batch_size: i32,
                                 request_id: i32, flags: OpQueryFlags,
                                 namespace: &str,
                                 number_to_skip: i32, number_to_return: i32,
                                 query: bson::Document,
                                 return_field_selector: Option<bson::Document>) -> Result<Cursor<'a, T>, String> {
        let result = Message::with_query(request_id, flags,
                                         namespace.to_owned(),
                                         number_to_skip, batch_size,
                                         query, return_field_selector);

        let message = match result {
            Ok(m) => m,
            Err(s) => return Err(s)
        };

        match message.write(stream) {
            Ok(_) => (),
            Err(s) => return Err(s)
        };

        let reply  = match Message::read(stream) {
            Ok(m) => m,
            Err(s) => return Err(s)
        };

        match Cursor::<T>::get_bson_and_cid_from_message(reply) {
            Some((buf, cursor_id)) => Ok(Cursor {
                request_id: request_id,
                namespace: namespace.to_owned(),
                batch_size: batch_size,
                cursor_id: cursor_id,
                limit: number_to_return,
                count: 0,
                buffer: buf,
                stream: stream }),
            None => Err("Invalid response received".to_owned()),
        }
    }

    pub fn query(stream: &'a mut T, request_id: i32, flags: OpQueryFlags,
                 namespace: &str, number_to_skip: i32,
                 number_to_return: i32, query: bson::Document,
                 return_field_selector: Option<bson::Document>) -> Result<Cursor<'a, T>, String> {

        Cursor::query_with_batch_size(stream, 20, request_id, flags,
                                      namespace, number_to_skip,
                                      number_to_return, query,
                                      return_field_selector)
    }

    fn new_get_more_request(&mut self) -> Message {
        Message::with_get_more(self.request_id,
                               self.namespace.to_owned(),
                               self.batch_size, self.cursor_id)
    }

    fn next_from_stream(&mut self) -> Option<bson::Document> {
        let get_more = self.new_get_more_request();

        match get_more.write(&mut self.stream) {
            Ok(_) => (),
            Err(_) => return None
        };

        let reply = match Message::read(&mut self.stream) {
            Ok(m) => m,
            Err(_) => return None
        };

        match Cursor::<T>::get_bson_and_cid_from_message(reply) {
            Some((v, _)) => {
                self.buffer.extend(v);
                self.buffer.pop_front()
            },
            None => None
        }
    }

    pub fn next_n(&mut self, n: i32) -> Vec<bson::Document> {
        let mut vec = vec![];

        for _ in 0..n {
            let bson_option = self.next();

            match bson_option {
                Some(bson) => vec.push(bson),
                None => break
            };
        }

        vec
    }

    pub fn next_batch(&mut self) -> Vec<bson::Document> {
        let n = self.batch_size;

        self.next_n(n)
    }
}

impl <'a, T> Iterator for Cursor<'a, T> where T: Read + Write + 'a {
    type Item = bson::Document;

    fn next(&mut self) -> Option<bson::Document> {
        if self.limit != 0 && self.count >= self.limit {
            return None;
        }

        self.count += 1;

        match self.buffer.pop_front() {
            Some(bson) => Some(bson),
            None => self.next_from_stream()
        }
    }
}
<commit_msg>added documentaton to the cursor module<commit_after>use bson;
use client::wire_protocol::flags::OpQueryFlags;
use client::wire_protocol::operations::Message;
use std::collections::vec_deque::VecDeque;
use std::io::{Read, Write};

/// Maintains a connection to the server and lazily returns documents from a
/// query.
///
/// # Fields
///
/// `request_id` - Uniquely identifies the request being sent.
/// `namespace` - The full qualified name of the collection,
///                          beginning with the database name and a period.
/// `batch_size` - How many documents to fetch at a given time from the server.
/// `cursor_id` - Uniquely identifies the cursor being returned by the reply.
pub struct Cursor<'a, T> where T: Read + Write + 'a {
    request_id: i32,
    namespace: String,
    batch_size: i32,
    cursor_id: i64,
    limit: i32,
    count: i32,
    buffer: VecDeque<bson::Document>,
    stream: &'a mut T,
}

impl <'a, T> Cursor<'a, T> where T: Read + Write + 'a {
    /// Gets the cursor id and BSON documents from a reply Message.
    ///
    /// # Arguments
    ///
    /// `message` - The reply message to get the documents from.
    ///
    /// # Return value.
    ///
    ///
    fn get_bson_and_cid_from_message(message: Message) -> Option<(VecDeque<bson::Document>, i64)> {
        match message {
            Message::OpReply { header: _, flags: _, cursor_id: cid,
                               starting_from: _, number_returned: _,
                               documents: docs } => {
                let mut v = VecDeque::new();

                for doc in docs {
                    v.push_back(doc);
                }

                Some((v, cid))
            },
            _ => None
        }
    }

    /// Executes a query where the batch size of the returned cursor is
    /// specified.
    ///
    /// # Arguments
    ///
    /// `stream` - The stream to read the input from and write the output to.
    /// `batch_size` - How many documents the cursor should return at a time.
    /// `request_id` - The request ID to be placed in the message header.
    /// `flags` - Bit vector of query options.
    /// `namespace` - The full qualified name of the collection, beginning with
    ///               the database name and a dot.
    /// `number_to_skip` - The number of initial documents to skip over in the
    ///                    query results.
    /// `number_to_return - The total number of documents that should be
    ///                     returned by the query.
    /// `return_field_selector - An optional projection of which fields should
    ///                          be present in the documents to be returned by
    ///                          the query.
    ///
    /// # Return value
    ///
    /// Returns the cursor for the query results on success, or an error string
    /// on failure.
    pub fn query_with_batch_size(stream: &'a mut T, batch_size: i32,
                                 request_id: i32, flags: OpQueryFlags,
                                 namespace: &str, number_to_skip: i32,
                                 number_to_return: i32, query: bson::Document,
                                 return_field_selector: Option<bson::Document>) -> Result<Cursor<'a, T>, String> {
        let result = Message::with_query(request_id, flags,
                                         namespace.to_owned(),
                                         number_to_skip, batch_size,
                                         query, return_field_selector);

        let message = match result {
            Ok(m) => m,
            Err(s) => return Err(s)
        };

        match message.write(stream) {
            Ok(_) => (),
            Err(s) => return Err(s)
        };

        let reply  = match Message::read(stream) {
            Ok(m) => m,
            Err(s) => return Err(s)
        };

        match Cursor::<T>::get_bson_and_cid_from_message(reply) {
            Some((buf, cursor_id)) => Ok(Cursor {
                request_id: request_id,
                namespace: namespace.to_owned(),
                batch_size: batch_size,
                cursor_id: cursor_id,
                limit: number_to_return,
                count: 0,
                buffer: buf,
                stream: stream }),
            None => Err("Invalid response received".to_owned()),
        }
    }

    /// Executes a query with the default batch size.
    ///
    /// # Arguments
    ///
    /// `stream` - The stream to read the input from and write the output to.
    /// `request_id` - The request ID to be placed in the message header.
    /// `flags` - Bit vector of query options.
    /// `namespace` - The full qualified name of the collection, beginning with
    ///               the database name and a dot.
    /// `number_to_skip` - The number of initial documents to skip over in the
    ///                    query results.
    /// `number_to_return - The total number of documents that should be
    ///                     returned by the query.
    /// `query` - Specifies which documents to return.
    /// `return_field_selector - An optional projection of which fields should
    ///                          be present in the documents to be returned by
    ///                          the query.
    ///
    /// # Return value
    ///
    /// Returns the cursor for the query results on success, or an error string
    /// on failure.
    pub fn query(stream: &'a mut T, request_id: i32, flags: OpQueryFlags,
                 namespace: &str, number_to_skip: i32,
                 number_to_return: i32, query: bson::Document,
                 return_field_selector: Option<bson::Document>) -> Result<Cursor<'a, T>, String> {

        Cursor::query_with_batch_size(stream, 20, request_id, flags,
                                      namespace, number_to_skip,
                                      number_to_return, query,
                                      return_field_selector)
    }

    /// Helper method to create a "get more" request.
    ///
    /// # Return value
    ///
    /// Returns the newly-created method.
    fn new_get_more_request(&mut self) -> Message {
        Message::with_get_more(self.request_id,
                               self.namespace.to_owned(),
                               self.batch_size, self.cursor_id)
    }

    /// Attempts read another batch of BSON documents from the stream.
    ///
    /// # Return value
    ///
    /// Returns the first BSON document returned from the stream, or `None` if
    /// there are no more documents to read.
    fn next_from_stream(&mut self) -> Option<bson::Document> {
        let get_more = self.new_get_more_request();

        match get_more.write(&mut self.stream) {
            Ok(_) => (),
            Err(_) => return None
        };

        let reply = match Message::read(&mut self.stream) {
            Ok(m) => m,
            Err(_) => return None
        };

        match Cursor::<T>::get_bson_and_cid_from_message(reply) {
            Some((v, _)) => {
                self.buffer.extend(v);
                self.buffer.pop_front()
            },
            None => None
        }
    }

    /// Attempts to read a specified number of BSON documents from the cursor.
    ///
    /// # Arguments
    ///
    /// `n` - The number of documents to read.
    ///
    /// # Return value
    ///
    /// Returns a vector containing the BSON documents that were read.
    pub fn next_n(&mut self, n: i32) -> Vec<bson::Document> {
        let mut vec = vec![];

        for _ in 0..n {
            let bson_option = self.next();

            match bson_option {
                Some(bson) => vec.push(bson),
                None => break
            };
        }

        vec
    }

    /// Attempts to read a batch of BSON documents from the cursor.
    ///
    /// # Return value
    ///
    /// Returns a vector containing the BSON documents that were read.
    pub fn next_batch(&mut self) -> Vec<bson::Document> {
        let n = self.batch_size;

        self.next_n(n)
    }
}

impl <'a, T> Iterator for Cursor<'a, T> where T: Read + Write + 'a {
    type Item = bson::Document;

    /// Attempts to read a BSON document from the cursor.
    ///
    /// # Return value
    ///
    /// Returns the document that was read, or `None` if there are no more
    /// documents to read.
    fn next(&mut self) -> Option<bson::Document> {
        if self.limit != 0 && self.count >= self.limit {
            return None;
        }

        self.count += 1;

        match self.buffer.pop_front() {
            Some(bson) => Some(bson),
            None => self.next_from_stream()
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::io;
use std::io::Write;
use std::path;
use std::process;

struct Project {
    root: tempdir::TempDir,
    files: Vec<(path::PathBuf, Vec<u8>)>,
}

impl Project {
    fn new() -> Project {
        Project {
            root: tempdir::TempDir::new("built_integration").unwrap(),
            files: Vec::new(),
        }
    }

    fn add_file<N: Into<path::PathBuf>, C: Into<Vec<u8>>>(
        &mut self,
        name: N,
        content: C,
    ) -> &mut Self {
        self.files.push((name.into(), content.into()));
        self
    }

    #[cfg(feature = "git2")]
    fn bootstrap(&mut self) -> &mut Self {
        let built_root = get_built_root();
        let features = if cfg!(feature = "git2") {
            r#"["git2"]"#
        } else {
            "[]"
        };
        self.add_file(
            "Cargo.toml",
            format!(
                r#"
[package]
name = "testbox"
version = "0.0.1"
build = "build.rs"

[build-dependencies]
built = {{ path = {:?}, features = {} }}"#,
                &built_root, &features,
            ),
        )
        .add_file(
            "build.rs",
            r#"
extern crate built;
fn main() {
    built::write_built_file().expect("writing failed");
}"#,
        );
        self
    }

    /// Hold on to the tempdir, it will be removed when dropped!
    fn create(self) -> io::Result<tempdir::TempDir> {
        fs::DirBuilder::new()
            .create(&self.root.path().join("src"))
            .unwrap();
        for (name, content) in self.files {
            let fname = self.root.path().join(name);
            let mut file = fs::File::create(&fname)?;
            file.write_all(&content)?;
        }
        Ok(self.root)
    }

    fn create_and_run(self) {
        let root = self.create().expect("Creating the project failed");
        Self::run(root.as_ref())
    }

    fn run(root: &std::path::Path) {
        let cargo_result = process::Command::new("cargo")
            .current_dir(&root)
            .arg("run")
            .output()
            .expect("cargo failed");
        if !cargo_result.status.success() {
            panic!(
                "cargo failed with {}",
                String::from_utf8_lossy(&cargo_result.stderr)
            );
        }
    }

    #[cfg(feature = "git2")]
    fn init_git(&self) -> git2::Repository {
        git2::Repository::init_opts(
            &self.root,
            git2::RepositoryInitOptions::new()
                .external_template(false)
                .mkdir(false)
                .no_reinit(true)
                .mkpath(false),
        )
        .expect("git-init failed")
    }
}

/// Tries to find built's Cargo.toml, panics if it ends up in /
fn get_built_root() -> path::PathBuf {
    env::current_exe()
        .map(|path| {
            let mut path = path;
            loop {
                if path.join("Cargo.toml").exists() {
                    break;
                }
                path = path::PathBuf::from(path.parent().unwrap());
            }
            path
        })
        .unwrap()
}

#[test]
fn new_testbox() {
    let mut p = Project::new();

    let built_root = get_built_root();

    p.add_file(
        "Cargo.toml",
        format!(
            "
[package]
name = \"testbox\"
version = \"1.2.3-rc1\"
authors = [\"Joe\", \"Bob\", \"Harry:Potter\"]
build = \"build.rs\"
description = \"xobtset\"
homepage = \"localhost\"

[dependencies]
chrono = \"0.4\"
semver = \"0.10\"
built = {{ path = {:?}, features=[\"git2\", \"chrono\", \"semver\"] }}

[build-dependencies]
built = {{ path = {:?}, features=[\"git2\", \"chrono\", \"semver\"] }}

[features]
default = [\"SuperAwesome\", \"MegaAwesome\"]
SuperAwesome = []
MegaAwesome = []",
            &built_root, &built_root
        ),
    );

    p.add_file(
        "build.rs",
        r#"
use std::env;
use std::path;
extern crate built;

fn main() {
    // Teleport to a CI-platform, should get detected
    env::set_var("CONTINUOUS_INTEGRATION", "1");

    let mut options = built::Options::default();
    options.set_dependencies(true);
    let src = env::var("CARGO_MANIFEST_DIR").unwrap();
    let dst = path::Path::new(&env::var("OUT_DIR").unwrap()).join("built.rs");
    built::write_built_file_with_opts(&options, src.as_ref(), &dst).unwrap();
}"#,
    );

    p.add_file(
        "src/main.rs",
        r#"
//! The testbox.

mod built_info {
    include!(concat!(env!("OUT_DIR"), "/built.rs"));
}

fn main() {
    assert_eq!(built_info::GIT_VERSION, None);
    assert_eq!(built_info::GIT_DIRTY, None);
    assert_eq!(built_info::GIT_COMMIT_HASH, None);
    assert_eq!(built_info::GIT_HEAD_REF, None);
    assert!(built_info::CI_PLATFORM.is_some());
    assert_eq!(built_info::PKG_VERSION, "1.2.3-rc1");
    assert_eq!(built_info::PKG_VERSION_MAJOR, "1");
    assert_eq!(built_info::PKG_VERSION_MINOR, "2");
    assert_eq!(built_info::PKG_VERSION_PATCH, "3");
    assert_eq!(built_info::PKG_VERSION_PRE, "rc1");
    assert_eq!(built_info::PKG_AUTHORS, "Joe:Bob:Harry:Potter");
    assert_eq!(built_info::PKG_NAME, "testbox");
    assert_eq!(built_info::PKG_DESCRIPTION, "xobtset");
    assert_eq!(built_info::PKG_HOMEPAGE, "localhost");
    assert!(built_info::NUM_JOBS > 0);
    assert!(built_info::OPT_LEVEL == "0");
    assert!(built_info::DEBUG);
    assert_eq!(built_info::PROFILE, "debug");
    assert_eq!(built_info::FEATURES,
               ["DEFAULT", "MEGAAWESOME", "SUPERAWESOME"]);
    assert_eq!(built_info::FEATURES_STR,
               "DEFAULT, MEGAAWESOME, SUPERAWESOME");
    assert_ne!(built_info::RUSTC_VERSION, "");
    assert_ne!(built_info::RUSTDOC_VERSION, "");
    assert_ne!(built_info::DEPENDENCIES_STR, "");
    assert_ne!(built_info::HOST, "");
    assert_ne!(built_info::TARGET, "");
    assert_ne!(built_info::RUSTC, "");
    assert_ne!(built_info::RUSTDOC, "");
    assert_ne!(built_info::CFG_TARGET_ARCH, "");
    assert_ne!(built_info::CFG_ENDIAN, "");
    assert_ne!(built_info::CFG_ENV, "");
    assert_ne!(built_info::CFG_FAMILY, "");
    assert_ne!(built_info::CFG_OS, "");
    assert_ne!(built_info::CFG_POINTER_WIDTH, "");

    assert!(built::util::parse_versions(built_info::DEPENDENCIES.iter())
        .any(|(name, ver)| name == "toml" && ver >= semver::Version::parse("0.1.0").unwrap()));

    assert!((chrono::offset::Utc::now() - built::util::strptime(built_info::BUILT_TIME_UTC)).num_days() <= 1);
}"#,
    );
    p.create_and_run();
}

#[test]
#[cfg(feature = "git2")]
fn clean_then_dirty_git() {
    let mut p = Project::new();
    p.bootstrap().add_file(
        "src/main.rs",
        r#"
mod built_info {
    include!(concat!(env!("OUT_DIR"), "/built.rs"));
}

fn main() {
    assert_eq!(built_info::GIT_DIRTY, Some(false));
}
"#,
    );
    let repo = p.init_git();
    let root = p.create().expect("Creating the project failed");

    let sig = git2::Signature::now("foo", "bar").unwrap();

    let mut idx = repo.index().unwrap();
    for p in &["src/main.rs", "build.rs"] {
        idx.add_path(path::Path::new(p)).unwrap();
    }
    idx.write().unwrap();
    repo.commit(
        Some("HEAD"),
        &sig,
        &sig,
        "Testing testing 1 2 3",
        &repo.find_tree(idx.write_tree().unwrap()).unwrap(),
        &[],
    )
    .unwrap();
    Project::run(root.as_ref());

    let mut f = std::fs::OpenOptions::new()
        .write(true)
        .truncate(true)
        .open(&root.path().join("src/main.rs"))
        .unwrap();
    f.write_all(
        r#"
mod built_info {
    include!(concat!(env!("OUT_DIR"), "/built.rs"));
}

fn main() {
    assert_eq!(built_info::GIT_DIRTY, Some(true));
}
"#
        .as_bytes(),
    )
    .unwrap();

    Project::run(root.as_ref());
}

#[test]
#[cfg(feature = "git2")]
fn empty_git() {
    // Issue #7, git can be there and still fail
    let mut p = Project::new();
    p.bootstrap().add_file(
        "src/main.rs",
        r#"
mod built_info {
    include!(concat!(env!("OUT_DIR"), "/built.rs"));
}

fn main() {}
"#,
    );
    p.init_git();
    p.create_and_run();
}
<commit_msg>Tests for repository and license<commit_after>use std::env;
use std::fs;
use std::io;
use std::io::Write;
use std::path;
use std::process;

struct Project {
    root: tempdir::TempDir,
    files: Vec<(path::PathBuf, Vec<u8>)>,
}

impl Project {
    fn new() -> Project {
        Project {
            root: tempdir::TempDir::new("built_integration").unwrap(),
            files: Vec::new(),
        }
    }

    fn add_file<N: Into<path::PathBuf>, C: Into<Vec<u8>>>(
        &mut self,
        name: N,
        content: C,
    ) -> &mut Self {
        self.files.push((name.into(), content.into()));
        self
    }

    #[cfg(feature = "git2")]
    fn bootstrap(&mut self) -> &mut Self {
        let built_root = get_built_root();
        let features = if cfg!(feature = "git2") {
            r#"["git2"]"#
        } else {
            "[]"
        };
        self.add_file(
            "Cargo.toml",
            format!(
                r#"
[package]
name = "testbox"
version = "0.0.1"
build = "build.rs"

[build-dependencies]
built = {{ path = {:?}, features = {} }}"#,
                &built_root, &features,
            ),
        )
        .add_file(
            "build.rs",
            r#"
extern crate built;
fn main() {
    built::write_built_file().expect("writing failed");
}"#,
        );
        self
    }

    /// Hold on to the tempdir, it will be removed when dropped!
    fn create(self) -> io::Result<tempdir::TempDir> {
        fs::DirBuilder::new()
            .create(&self.root.path().join("src"))
            .unwrap();
        for (name, content) in self.files {
            let fname = self.root.path().join(name);
            let mut file = fs::File::create(&fname)?;
            file.write_all(&content)?;
        }
        Ok(self.root)
    }

    fn create_and_run(self) {
        let root = self.create().expect("Creating the project failed");
        Self::run(root.as_ref())
    }

    fn run(root: &std::path::Path) {
        let cargo_result = process::Command::new("cargo")
            .current_dir(&root)
            .arg("run")
            .output()
            .expect("cargo failed");
        if !cargo_result.status.success() {
            panic!(
                "cargo failed with {}",
                String::from_utf8_lossy(&cargo_result.stderr)
            );
        }
    }

    #[cfg(feature = "git2")]
    fn init_git(&self) -> git2::Repository {
        git2::Repository::init_opts(
            &self.root,
            git2::RepositoryInitOptions::new()
                .external_template(false)
                .mkdir(false)
                .no_reinit(true)
                .mkpath(false),
        )
        .expect("git-init failed")
    }
}

/// Tries to find built's Cargo.toml, panics if it ends up in /
fn get_built_root() -> path::PathBuf {
    env::current_exe()
        .map(|path| {
            let mut path = path;
            loop {
                if path.join("Cargo.toml").exists() {
                    break;
                }
                path = path::PathBuf::from(path.parent().unwrap());
            }
            path
        })
        .unwrap()
}

#[test]
fn new_testbox() {
    let mut p = Project::new();

    let built_root = get_built_root();

    p.add_file(
        "Cargo.toml",
        format!(
            "
[package]
name = \"testbox\"
version = \"1.2.3-rc1\"
authors = [\"Joe\", \"Bob\", \"Harry:Potter\"]
build = \"build.rs\"
description = \"xobtset\"
homepage = \"localhost\"
repository = \"https://dev.example.com/sources/testbox/\"
license = \"MIT\"

[dependencies]
chrono = \"0.4\"
semver = \"0.10\"
built = {{ path = {:?}, features=[\"git2\", \"chrono\", \"semver\"] }}

[build-dependencies]
built = {{ path = {:?}, features=[\"git2\", \"chrono\", \"semver\"] }}

[features]
default = [\"SuperAwesome\", \"MegaAwesome\"]
SuperAwesome = []
MegaAwesome = []",
            &built_root, &built_root
        ),
    );

    p.add_file(
        "build.rs",
        r#"
use std::env;
use std::path;
extern crate built;

fn main() {
    // Teleport to a CI-platform, should get detected
    env::set_var("CONTINUOUS_INTEGRATION", "1");

    let mut options = built::Options::default();
    options.set_dependencies(true);
    let src = env::var("CARGO_MANIFEST_DIR").unwrap();
    let dst = path::Path::new(&env::var("OUT_DIR").unwrap()).join("built.rs");
    built::write_built_file_with_opts(&options, src.as_ref(), &dst).unwrap();
}"#,
    );

    p.add_file(
        "src/main.rs",
        r#"
//! The testbox.

mod built_info {
    include!(concat!(env!("OUT_DIR"), "/built.rs"));
}

fn main() {
    assert_eq!(built_info::GIT_VERSION, None);
    assert_eq!(built_info::GIT_DIRTY, None);
    assert_eq!(built_info::GIT_COMMIT_HASH, None);
    assert_eq!(built_info::GIT_HEAD_REF, None);
    assert!(built_info::CI_PLATFORM.is_some());
    assert_eq!(built_info::PKG_VERSION, "1.2.3-rc1");
    assert_eq!(built_info::PKG_VERSION_MAJOR, "1");
    assert_eq!(built_info::PKG_VERSION_MINOR, "2");
    assert_eq!(built_info::PKG_VERSION_PATCH, "3");
    assert_eq!(built_info::PKG_VERSION_PRE, "rc1");
    assert_eq!(built_info::PKG_AUTHORS, "Joe:Bob:Harry:Potter");
    assert_eq!(built_info::PKG_NAME, "testbox");
    assert_eq!(built_info::PKG_DESCRIPTION, "xobtset");
    assert_eq!(built_info::PKG_HOMEPAGE, "localhost");
    assert_eq!(built_info::PKG_LICENSE, "MIT");
    assert_eq!(built_info::PKG_REPOSITORY, "https://dev.example.com/sources/testbox/");
    assert!(built_info::NUM_JOBS > 0);
    assert!(built_info::OPT_LEVEL == "0");
    assert!(built_info::DEBUG);
    assert_eq!(built_info::PROFILE, "debug");
    assert_eq!(built_info::FEATURES,
               ["DEFAULT", "MEGAAWESOME", "SUPERAWESOME"]);
    assert_eq!(built_info::FEATURES_STR,
               "DEFAULT, MEGAAWESOME, SUPERAWESOME");
    assert_ne!(built_info::RUSTC_VERSION, "");
    assert_ne!(built_info::RUSTDOC_VERSION, "");
    assert_ne!(built_info::DEPENDENCIES_STR, "");
    assert_ne!(built_info::HOST, "");
    assert_ne!(built_info::TARGET, "");
    assert_ne!(built_info::RUSTC, "");
    assert_ne!(built_info::RUSTDOC, "");
    assert_ne!(built_info::CFG_TARGET_ARCH, "");
    assert_ne!(built_info::CFG_ENDIAN, "");
    assert_ne!(built_info::CFG_ENV, "");
    assert_ne!(built_info::CFG_FAMILY, "");
    assert_ne!(built_info::CFG_OS, "");
    assert_ne!(built_info::CFG_POINTER_WIDTH, "");

    assert!(built::util::parse_versions(built_info::DEPENDENCIES.iter())
        .any(|(name, ver)| name == "toml" && ver >= semver::Version::parse("0.1.0").unwrap()));

    assert!((chrono::offset::Utc::now() - built::util::strptime(built_info::BUILT_TIME_UTC)).num_days() <= 1);
}"#,
    );
    p.create_and_run();
}

#[test]
#[cfg(feature = "git2")]
fn clean_then_dirty_git() {
    let mut p = Project::new();
    p.bootstrap().add_file(
        "src/main.rs",
        r#"
mod built_info {
    include!(concat!(env!("OUT_DIR"), "/built.rs"));
}

fn main() {
    assert_eq!(built_info::GIT_DIRTY, Some(false));
}
"#,
    );
    let repo = p.init_git();
    let root = p.create().expect("Creating the project failed");

    let sig = git2::Signature::now("foo", "bar").unwrap();

    let mut idx = repo.index().unwrap();
    for p in &["src/main.rs", "build.rs"] {
        idx.add_path(path::Path::new(p)).unwrap();
    }
    idx.write().unwrap();
    repo.commit(
        Some("HEAD"),
        &sig,
        &sig,
        "Testing testing 1 2 3",
        &repo.find_tree(idx.write_tree().unwrap()).unwrap(),
        &[],
    )
    .unwrap();
    Project::run(root.as_ref());

    let mut f = std::fs::OpenOptions::new()
        .write(true)
        .truncate(true)
        .open(&root.path().join("src/main.rs"))
        .unwrap();
    f.write_all(
        r#"
mod built_info {
    include!(concat!(env!("OUT_DIR"), "/built.rs"));
}

fn main() {
    assert_eq!(built_info::GIT_DIRTY, Some(true));
}
"#
        .as_bytes(),
    )
    .unwrap();

    Project::run(root.as_ref());
}

#[test]
#[cfg(feature = "git2")]
fn empty_git() {
    // Issue #7, git can be there and still fail
    let mut p = Project::new();
    p.bootstrap().add_file(
        "src/main.rs",
        r#"
mod built_info {
    include!(concat!(env!("OUT_DIR"), "/built.rs"));
}

fn main() {}
"#,
    );
    p.init_git();
    p.create_and_run();
}
<|endoftext|>


<commit_before>use super::{function, trait_impls};
use crate::{
    analysis::flags::Info,
    codegen::general::{
        self, cfg_deprecated, derives, version_condition, version_condition_string,
    },
    config::gobjects::GObject,
    env::Env,
    file_saver,
    library::*,
    nameutil::{bitfield_member_name, use_glib_type},
    traits::*,
};
use std::{
    io::{prelude::*, Result},
    path::Path,
};

pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec<String>) {
    if env.analysis.flags.is_empty() {
        return;
    }

    let path = root_path.join("flags.rs");
    file_saver::save_to_file(path, env.config.make_backup, |w| {
        general::start_comments(w, &env.config)?;
        general::uses(w, env, &env.analysis.flags_imports)?;
        writeln!(w)?;

        mod_rs.push("\nmod flags;".into());
        for flags_analysis in &env.analysis.flags {
            let config = &env.config.objects[&flags_analysis.full_name];
            let flags = flags_analysis.type_(&env.library);

            if let Some(cfg) = version_condition_string(env, flags.version, false, 0) {
                mod_rs.push(cfg);
            }
            mod_rs.push(format!("pub use self::flags::{};", flags.name));
            generate_flags(env, w, flags, config, flags_analysis)?;
        }

        Ok(())
    });
}

#[allow(clippy::write_literal)]
fn generate_flags(
    env: &Env,
    w: &mut dyn Write,
    flags: &Bitfield,
    config: &GObject,
    analysis: &Info,
) -> Result<()> {
    let sys_crate_name = env.main_sys_crate_name();
    cfg_deprecated(w, env, flags.deprecated_version, false, 0)?;
    version_condition(w, env, flags.version, false, 0)?;
    writeln!(w, "bitflags! {{")?;
    if config.must_use {
        writeln!(w, "    #[must_use]")?;
    }

    if let Some(ref d) = config.derives {
        derives(w, &d, 1)?;
    }

    writeln!(w, "    pub struct {}: u32 {{", flags.name)?;
    for member in &flags.members {
        let member_config = config.members.matched(&member.name);
        let generate = member_config.iter().all(|m| m.status.need_generate());
        if !generate {
            continue;
        }

        let name = bitfield_member_name(&member.name);
        let val: i64 = member.value.parse().unwrap();
        let deprecated_version = member_config
            .iter()
            .filter_map(|m| m.deprecated_version)
            .next();
        let version = member_config.iter().filter_map(|m| m.version).next();
        cfg_deprecated(w, env, deprecated_version, false, 2)?;
        version_condition(w, env, version, false, 2)?;
        writeln!(w, "\t\tconst {} = {};", name, val as u32)?;
    }

    writeln!(
        w,
        "    }}
}}"
    )?;

    let functions = analysis
        .functions
        .iter()
        .filter(|f| f.status.need_generate())
        .collect::<Vec<_>>();

    if !functions.is_empty() {
        let static_tostring = analysis
            .specials
            .get(&crate::analysis::special_functions::Type::Display)
            .and_then(|f| if f.returns_static_ref { Some(f) } else { None });

        writeln!(w)?;
        version_condition(w, env, flags.version, false, 0)?;
        write!(w, "impl {} {{", analysis.name)?;
        for func_analysis in functions {
            if Some(&func_analysis.glib_name) == static_tostring.map(|t| &t.glib_name) {
                function::generate_static_to_str(w, env, func_analysis)?;
            } else {
                function::generate(w, env, func_analysis, false, false, 1)?;
            }
        }
        writeln!(w, "}}")?;
    }

    trait_impls::generate(
        w,
        env,
        &analysis.name,
        &analysis.functions,
        &analysis.specials,
        None,
    )?;

    writeln!(w)?;

    version_condition(w, env, flags.version, false, 0)?;
    writeln!(
        w,
        "#[doc(hidden)]
impl ToGlib for {name} {{
    type GlibType = {sys_crate_name}::{ffi_name};

    fn to_glib(&self) -> {sys_crate_name}::{ffi_name} {{
        self.bits()
    }}
}}
",
        sys_crate_name = sys_crate_name,
        name = flags.name,
        ffi_name = flags.c_type
    )?;

    let assert = if env.config.generate_safety_asserts {
        "skip_assert_initialized!();\n\t\t"
    } else {
        ""
    };

    version_condition(w, env, flags.version, false, 0)?;
    writeln!(
        w,
        "#[doc(hidden)]
impl FromGlib<{sys_crate_name}::{ffi_name}> for {name} {{
    fn from_glib(value: {sys_crate_name}::{ffi_name}) -> {name} {{
        {assert}{name}::from_bits_truncate(value)
    }}
}}
",
        sys_crate_name = sys_crate_name,
        name = flags.name,
        ffi_name = flags.c_type,
        assert = assert
    )?;

    if let Some(ref get_type) = flags.glib_get_type {
        let configured_functions = config.functions.matched("get_type");
        let version = std::iter::once(flags.version)
            .chain(configured_functions.iter().map(|f| f.version))
            .max()
            .flatten();

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl StaticType for {name} {{
    fn static_type() -> Type {{
        unsafe {{ from_glib({sys_crate_name}::{get_type}()) }}
    }}
}}",
            sys_crate_name = sys_crate_name,
            name = flags.name,
            get_type = get_type
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl<'a> FromValueOptional<'a> for {name} {{
    unsafe fn from_value_optional(value: &{gvalue}) -> Option<Self> {{
        Some(FromValue::from_value(value))
    }}
}}",
            name = flags.name,
            gvalue = use_glib_type(env, "Value"),
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl<'a> FromValue<'a> for {name} {{
    unsafe fn from_value(value: &{gvalue}) -> Self {{
        from_glib({glib}(value.to_glib_none().0))
    }}
}}",
            name = flags.name,
            glib = use_glib_type(env, "gobject_ffi::g_value_get_flags"),
            gvalue = use_glib_type(env, "Value"),
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl SetValue for {name} {{
    unsafe fn set_value(value: &mut {gvalue}, this: &Self) {{
        {glib}(value.to_glib_none_mut().0, this.to_glib())
    }}
}}",
            name = flags.name,
            glib = use_glib_type(env, "gobject_ffi::g_value_set_flags"),
            gvalue = use_glib_type(env, "Value"),
        )?;

        writeln!(w)?;
    }

    Ok(())
}
<commit_msg>codegen/flags: Add missing display trait generation<commit_after>use super::{function, trait_impls};
use crate::{
    analysis::flags::Info,
    codegen::general::{
        self, cfg_deprecated, derives, version_condition, version_condition_string,
    },
    config::gobjects::GObject,
    env::Env,
    file_saver,
    library::*,
    nameutil::{bitfield_member_name, use_glib_type},
    traits::*,
};
use std::{
    io::{prelude::*, Result},
    path::Path,
};

pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec<String>) {
    if env.analysis.flags.is_empty() {
        return;
    }

    let path = root_path.join("flags.rs");
    file_saver::save_to_file(path, env.config.make_backup, |w| {
        general::start_comments(w, &env.config)?;
        general::uses(w, env, &env.analysis.flags_imports)?;
        writeln!(w)?;

        mod_rs.push("\nmod flags;".into());
        for flags_analysis in &env.analysis.flags {
            let config = &env.config.objects[&flags_analysis.full_name];
            let flags = flags_analysis.type_(&env.library);

            if let Some(cfg) = version_condition_string(env, flags.version, false, 0) {
                mod_rs.push(cfg);
            }
            mod_rs.push(format!("pub use self::flags::{};", flags.name));
            generate_flags(env, w, flags, config, flags_analysis)?;
        }

        Ok(())
    });
}

#[allow(clippy::write_literal)]
fn generate_flags(
    env: &Env,
    w: &mut dyn Write,
    flags: &Bitfield,
    config: &GObject,
    analysis: &Info,
) -> Result<()> {
    let sys_crate_name = env.main_sys_crate_name();
    cfg_deprecated(w, env, flags.deprecated_version, false, 0)?;
    version_condition(w, env, flags.version, false, 0)?;
    writeln!(w, "bitflags! {{")?;
    if config.must_use {
        writeln!(w, "    #[must_use]")?;
    }

    if let Some(ref d) = config.derives {
        derives(w, &d, 1)?;
    }

    writeln!(w, "    pub struct {}: u32 {{", flags.name)?;
    for member in &flags.members {
        let member_config = config.members.matched(&member.name);
        let generate = member_config.iter().all(|m| m.status.need_generate());
        if !generate {
            continue;
        }

        let name = bitfield_member_name(&member.name);
        let val: i64 = member.value.parse().unwrap();
        let deprecated_version = member_config
            .iter()
            .filter_map(|m| m.deprecated_version)
            .next();
        let version = member_config.iter().filter_map(|m| m.version).next();
        cfg_deprecated(w, env, deprecated_version, false, 2)?;
        version_condition(w, env, version, false, 2)?;
        writeln!(w, "\t\tconst {} = {};", name, val as u32)?;
    }

    writeln!(
        w,
        "    }}
}}"
    )?;

    let functions = analysis
        .functions
        .iter()
        .filter(|f| f.status.need_generate())
        .collect::<Vec<_>>();

    if !functions.is_empty() {
        let static_tostring = analysis
            .specials
            .get(&crate::analysis::special_functions::Type::Display)
            .and_then(|f| if f.returns_static_ref { Some(f) } else { None });

        writeln!(w)?;
        version_condition(w, env, flags.version, false, 0)?;
        write!(w, "impl {} {{", analysis.name)?;
        for func_analysis in functions {
            if Some(&func_analysis.glib_name) == static_tostring.map(|t| &t.glib_name) {
                function::generate_static_to_str(w, env, func_analysis)?;
            } else {
                function::generate(w, env, func_analysis, false, false, 1)?;
            }
        }
        writeln!(w, "}}")?;
    }

    trait_impls::generate(
        w,
        env,
        &analysis.name,
        &analysis.functions,
        &analysis.specials,
        None,
    )?;

    writeln!(w)?;

    if config.generate_display_trait {
        // Generate Display trait implementation.
        version_condition(w, env, flags.version, false, 0)?;
        writeln!(
            w,
            "impl fmt::Display for {0} {{\n\
            \tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{\n\
            \t\t<Self as fmt::Debug>::fmt(self, f)\n\
            \t}}\n\
            }}\n",
            flags.name
        )?;
    }

    version_condition(w, env, flags.version, false, 0)?;
    writeln!(
        w,
        "#[doc(hidden)]
impl ToGlib for {name} {{
    type GlibType = {sys_crate_name}::{ffi_name};

    fn to_glib(&self) -> {sys_crate_name}::{ffi_name} {{
        self.bits()
    }}
}}
",
        sys_crate_name = sys_crate_name,
        name = flags.name,
        ffi_name = flags.c_type
    )?;

    let assert = if env.config.generate_safety_asserts {
        "skip_assert_initialized!();\n\t\t"
    } else {
        ""
    };

    version_condition(w, env, flags.version, false, 0)?;
    writeln!(
        w,
        "#[doc(hidden)]
impl FromGlib<{sys_crate_name}::{ffi_name}> for {name} {{
    fn from_glib(value: {sys_crate_name}::{ffi_name}) -> {name} {{
        {assert}{name}::from_bits_truncate(value)
    }}
}}
",
        sys_crate_name = sys_crate_name,
        name = flags.name,
        ffi_name = flags.c_type,
        assert = assert
    )?;

    if let Some(ref get_type) = flags.glib_get_type {
        let configured_functions = config.functions.matched("get_type");
        let version = std::iter::once(flags.version)
            .chain(configured_functions.iter().map(|f| f.version))
            .max()
            .flatten();

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl StaticType for {name} {{
    fn static_type() -> Type {{
        unsafe {{ from_glib({sys_crate_name}::{get_type}()) }}
    }}
}}",
            sys_crate_name = sys_crate_name,
            name = flags.name,
            get_type = get_type
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl<'a> FromValueOptional<'a> for {name} {{
    unsafe fn from_value_optional(value: &{gvalue}) -> Option<Self> {{
        Some(FromValue::from_value(value))
    }}
}}",
            name = flags.name,
            gvalue = use_glib_type(env, "Value"),
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl<'a> FromValue<'a> for {name} {{
    unsafe fn from_value(value: &{gvalue}) -> Self {{
        from_glib({glib}(value.to_glib_none().0))
    }}
}}",
            name = flags.name,
            glib = use_glib_type(env, "gobject_ffi::g_value_get_flags"),
            gvalue = use_glib_type(env, "Value"),
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl SetValue for {name} {{
    unsafe fn set_value(value: &mut {gvalue}, this: &Self) {{
        {glib}(value.to_glib_none_mut().0, this.to_glib())
    }}
}}",
            name = flags.name,
            glib = use_glib_type(env, "gobject_ffi::g_value_set_flags"),
            gvalue = use_glib_type(env, "Value"),
        )?;

        writeln!(w)?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::char;
use std::io;

use common::{err, hex};

// base64 encoding:
// 00 - 25 : A - Z
// 26 - 51 : a - z
// 52 - 61 : 0 - 9
// 62 : +
// 63 : /
fn u8_to_base64(index: u8) -> Result<char, err::Error> {
	let ord: u8 = match index {
		0 ... 25	=> index + 65,
		26 ... 51	=> index + 71,
		52 ... 61	=> index - 4,
		62	        => 43,
		63	        => 47,
		_	        => return Err(err::make_error(format!("base64 index out of range: {}", index))),
	};

	match char::from_u32(ord as u32) {
		Some(v)	=> Ok(v),
		None	=> Err(err::make_error(format!("bad ordinal: {}", ord))),
	}
}

fn base64_to_u8(b64char: char) -> Result<u8, err::Error> {
    let r = match b64char as u8 {
        65 ... 90   => b64char as u8 - 65,
        97 ... 122  => b64char as u8 - 71,
        48 ... 57   => b64char as u8 + 4,
        43          => 62,
        47          => 63,
        _           => return mkerr!(format!("invalid base64 character: {}", b64char))
    };
    Ok(r)
}

pub fn raw_to_base64(input: Vec<u8>) -> Result<String, err::Error> {
	let mut index: usize	= 0;
	let mut v		= Vec::new();
	let mut output		= String::new();
	let mut pad: usize	= 0;

	while index < input.len() {
		if (index + 3 > input.len()) {
			pad =  (index + 3) - input.len();

			for i in 0..(3-pad) {
				v.push(input[index+i]);
			}

			for i in 0..pad {
				v.push(0);
			}

		} else {
			v.push(input[index]);
			v.push(input[index + 1]);
			v.push(input[index + 2]);
		}
		index += 3;

		let mut b64index: u8 = v[0] >> 2;
		let mut b64char: char = try!(u8_to_base64(b64index));
		output.push(b64char);

		b64index = v[0] << 6;
		b64index = b64index >> 2 | v[1] >> 4;
		b64char = try!(u8_to_base64(b64index));
		output.push(b64char);

		if pad == 2 {
			output.push_str("==");
			break;
		}

		b64index = v[1] & 0xF;
		b64index = b64index << 2 | v[2] >> 6;

		b64char = try!(u8_to_base64(b64index));
		output.push(b64char);

		if pad == 1 {
			output.push_str("=");
			break;
		}

		b64index = v[2] & 0x3F;
		b64char = try!(u8_to_base64(b64index));
		output.push(b64char);

		v.clear();
	}

	return Ok(output);
}

pub fn base64_to_raw(input: &str) -> Result<Vec<u8>, err::Error> {
    let mut buf: Vec<char> = Vec::new();
    let mut output = Vec::new();

    for b64char in input.chars() {
        buf.push(b64char);

        if (buf.len() == 4 && b64char != '=') {
            let b1 = try!(base64_to_u8(buf[0]));
            let b2 = try!(base64_to_u8(buf[1]));
            let b3 = try!(base64_to_u8(buf[2]));
            let b4 = try!(base64_to_u8(buf[3]));

            let v = vec![b1 << 2 | b2 >> 4, b2 << 4 | b3 >> 2, b3 << 6 | b4];
            output.extend(v);
            buf.clear();
        }
    }

    if buf.len() > 0 {
        match buf.iter().filter(|&c| *c == '=').count() {
        2   => {
            let b1 = try!(base64_to_u8(buf[0]));
            let b2 = try!(base64_to_u8(buf[1]));
            output.push(b1 << 2 | b2 >> 4);
            }
        1   => {
            let b1 = try!(base64_to_u8(buf[0]));
            let b2 = try!(base64_to_u8(buf[1]));
            let b3 = try!(base64_to_u8(buf[2]));
            output.extend(vec![b1 << 2 | b2 >> 4, b2 << 4 | b3 >> 2]);
            },
        _   => return mkerr!("invalid base64 input")
        };
    }

    Ok(output)
}

pub fn hex_to_base64(input: &str) -> Result<String, err::Error> {
	let r: Result<Vec<u8>, err::Error> = hex::hex_to_raw(input);

	let raw: Vec<u8> = match r {
		Ok(v)	=> v,
		Err(e)	=> return Err(err::make_error(String::from(e))),
	};

	let r: Result<String, err::Error> = raw_to_base64(raw);

	match r {
		Ok(v)	=> Ok(v),
		Err(e)	=> Err(err::make_error(String::from("error"))),
	}
    Ok(try!(raw_to_base64(
}

macro_rules! b64d {
    ( $x : expr ) => ( try! ( base64::base64_to_raw( $x ) ) );
}

<commit_msg>Fixing the warnings. Just commented some new code so that build will succeed. Not tested.<commit_after>use std::char;
use std::io;

use common::{err, hex};

// base64 encoding:
// 00 - 25 : A - Z
// 26 - 51 : a - z
// 52 - 61 : 0 - 9
// 62 : +
// 63 : /
fn u8_to_base64(index: u8) -> Result<char, err::Error> {
	let ord: u8 = match index {
		0 ... 25	=> index + 65,
		26 ... 51	=> index + 71,
		52 ... 61	=> index - 4,
		62	        => 43,
		63	        => 47,
		_	        => return Err(err::make_error(format!("base64 index out of range: {}", index))),
	};

	match char::from_u32(ord as u32) {
		Some(v)	=> Ok(v),
		None	=> Err(err::make_error(format!("bad ordinal: {}", ord))),
	}
}

fn base64_to_u8(b64char: char) -> Result<u8, err::Error> {
    let r = match b64char as u8 {
        65 ... 90   => b64char as u8 - 65,
        97 ... 122  => b64char as u8 - 71,
        48 ... 57   => b64char as u8 + 4,
        43          => 62,
        47          => 63,
        _           => return mkerr!(format!("invalid base64 character: {}", b64char))
    };
    Ok(r)
}

pub fn raw_to_base64(input: Vec<u8>) -> Result<String, err::Error> {
	let mut index: usize	= 0;
	let mut v		= Vec::new();
	let mut output		= String::new();
	let mut pad: usize	= 0;

	while index < input.len() {
		if (index + 3 > input.len()) {
			pad =  (index + 3) - input.len();

			for i in 0..(3-pad) {
				v.push(input[index+i]);
			}

			for i in 0..pad {
				v.push(0);
			}

		} else {
			v.push(input[index]);
			v.push(input[index + 1]);
			v.push(input[index + 2]);
		}
		index += 3;

		let mut b64index: u8 = v[0] >> 2;
		let mut b64char: char = try!(u8_to_base64(b64index));
		output.push(b64char);

		b64index = v[0] << 6;
		b64index = b64index >> 2 | v[1] >> 4;
		b64char = try!(u8_to_base64(b64index));
		output.push(b64char);

		if pad == 2 {
			output.push_str("==");
			break;
		}

		b64index = v[1] & 0xF;
		b64index = b64index << 2 | v[2] >> 6;

		b64char = try!(u8_to_base64(b64index));
		output.push(b64char);

		if pad == 1 {
			output.push_str("=");
			break;
		}

		b64index = v[2] & 0x3F;
		b64char = try!(u8_to_base64(b64index));
		output.push(b64char);

		v.clear();
	}

	return Ok(output);
}

pub fn base64_to_raw(input: &str) -> Result<Vec<u8>, err::Error> {
    let mut buf: Vec<char> = Vec::new();
    let mut output = Vec::new();

    for b64char in input.chars() {
        buf.push(b64char);

        if (buf.len() == 4 && b64char != '=') {
            let b1 = try!(base64_to_u8(buf[0]));
            let b2 = try!(base64_to_u8(buf[1]));
            let b3 = try!(base64_to_u8(buf[2]));
            let b4 = try!(base64_to_u8(buf[3]));

            let v = vec![b1 << 2 | b2 >> 4, b2 << 4 | b3 >> 2, b3 << 6 | b4];
            output.extend(v);
            buf.clear();
        }
    }

    if buf.len() > 0 {
        match buf.iter().filter(|&c| *c == '=').count() {
        2   => {
            let b1 = try!(base64_to_u8(buf[0]));
            let b2 = try!(base64_to_u8(buf[1]));
            output.push(b1 << 2 | b2 >> 4);
            }
        1   => {
            let b1 = try!(base64_to_u8(buf[0]));
            let b2 = try!(base64_to_u8(buf[1]));
            let b3 = try!(base64_to_u8(buf[2]));
            output.extend(vec![b1 << 2 | b2 >> 4, b2 << 4 | b3 >> 2]);
            },
        _   => return mkerr!("invalid base64 input")
        };
    }

    Ok(output)
}

pub fn hex_to_base64(input: &str) -> Result<String, err::Error> {
	let r: Result<Vec<u8>, err::Error> = hex::hex_to_raw(input);

	let raw: Vec<u8> = match r {
		Ok(v)	=> v,
		Err(e)	=> return Err(err::make_error(String::from(e))),
	};

	let r: Result<String, err::Error> = raw_to_base64(raw);

	match r {
		Ok(v)	=> Ok(v),
		Err(e)	=> Err(err::make_error(String::from("error"))),
	}
    //Ok(try!(raw_to_base64(
}

macro_rules! b64d {
    ( $x : expr ) => ( try! ( base64::base64_to_raw( $x ) ) );
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::marker::PhantomData;
use super::*;
use auth;
use error;

///Trait to generalize over paginated views of API results.
pub trait Cursor {
    ///What type is being returned by the API call?
    type Item;

    ///Returns a numeric reference to the previous page of results.
    fn previous_cursor_id(&self) -> i64;
    ///Returns a numeric reference to the next page of results.
    fn next_cursor_id(&self) -> i64;
    ///Consumes the cursor and returns the collection of results from inside.
    fn into_inner(self) -> Vec<Self::Item>;
}

///Represents a paginated list of results, such as the users who follow a specific user or the
///lists owned by that user.
///
///Implemented as an iterator that lazily loads a page of results at a time, but returns a single
///item per-iteration. See examples in [the user module-level documentation][user-mod].
///
///[user-mod]: user/index.html
pub struct CursorIter<'a, T>
    where T: Cursor + FromJson
{
    link: &'static str,
    con_token: &'a auth::Token<'a>,
    access_token: &'a auth::Token<'a>,
    user_id: Option<UserID<'a>>,
    ///The number of results returned in one network call.
    ///
    ///Certain calls set their own minimums and maximums for what this value can be. Furthermore,
    ///some calls don't allow you to set the size of the pages at all. Refer to the individual
    ///methods' documentation for specifics.
    pub page_size: Option<i32>,
    ///Numeric reference to the previous page of results.
    ///
    ///This value is intended to be automatically set and used as part of this struct's Iterator
    ///implementation. It is made available for those who wish to manually manage network calls and
    ///pagination.
    pub previous_cursor: i64,
    ///Numeric reference to the next page of results. A value of zero indicates that the current
    ///page of results is the last page of the cursor.
    ///
    ///This value is intended to be automatically set and used as part of this struct's Iterator
    ///implementation. It is made available for those who wish to manually manage network calls and
    ///pagination.
    pub next_cursor: i64,
    iter: Option<ResponseIter<T::Item>>,
    _marker: PhantomData<T>,
}

impl<'a, T> CursorIter<'a, T>
    where T: Cursor + FromJson
{
    ///Sets the number of results returned in a single network call.
    ///
    ///Certain calls set their own minimums and maximums for what this value can be. Furthermore,
    ///some calls don't allow you to set the size of the pages at all. Refer to the individual
    ///methods' documentation for specifics. If this method is called for a response that does not
    ///accept changing the page size, no change to the underlying struct will occur.
    ///
    ///Calling this function will invalidate any current results, if any were previously loaded.
    pub fn with_page_size(self, page_size: i32) -> CursorIter<'a, T> {
        if self.page_size.is_some() {
            CursorIter {
                link: self.link,
                con_token: self.con_token,
                access_token: self.access_token,
                user_id: self.user_id,
                page_size: Some(page_size),
                previous_cursor: -1,
                next_cursor: -1,
                iter: None,
                _marker: self._marker,
            }
        }
        else {
            self
        }
    }

    ///Loads the next page of results.
    ///
    ///This is intended to be used as part of this struct's Iterator implementation. It is provided
    ///as a convenience for those who wish to manage network calls and pagination manually.
    pub fn call(&self) -> Result<Response<T>, error::Error> {
        let mut params = HashMap::new();
        if let Some(ref id) = self.user_id {
            add_name_param(&mut params, id);
        }
        add_param(&mut params, "cursor", self.next_cursor.to_string());
        if let Some(count) = self.page_size {
            add_param(&mut params, "count", count.to_string());
        }

        let mut resp = try!(auth::get(self.link, self.con_token, self.access_token, Some(&params)));

        parse_response(&mut resp)
    }

    ///Creates a new instance of CursorIter, with the given parameters and empty initial results.
    pub fn new(link: &'static str, con_token: &'a auth::Token, access_token: &'a auth::Token,
               user_id: Option<UserID<'a>>, page_size: Option<i32>) -> CursorIter<'a, T> {
        CursorIter {
            link: link,
            con_token: con_token,
            access_token: access_token,
            user_id: user_id,
            page_size: page_size,
            previous_cursor: -1,
            next_cursor: -1,
            iter: None,
            _marker: PhantomData,
        }
    }
}

impl<'a, T> Iterator for CursorIter<'a, T>
    where T: Cursor + FromJson
{
    type Item = Result<Response<T::Item>, error::Error>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(ref mut results) = self.iter {
            if let Some(item) = results.next() {
                return Some(Ok(item));
            }
            else if self.next_cursor == 0 {
                return None;
            }
        }

        match self.call() {
            Ok(resp) => {
                self.previous_cursor = resp.response.previous_cursor_id();
                self.next_cursor = resp.response.next_cursor_id();

                let resp = Response {
                    rate_limit: resp.rate_limit,
                    rate_limit_remaining: resp.rate_limit_remaining,
                    rate_limit_reset: resp.rate_limit_reset,
                    response: resp.response.into_inner(),
                };

                let mut iter = resp.into_iter();
                let first = iter.next();
                self.iter = Some(iter);

                match first {
                    Some(item) => Some(Ok(item)),
                    None => None,
                }
            },
            Err(err) => Some(Err(err)),
        }
    }
}
<commit_msg>add must_use to CursorIter<commit_after>use std::collections::HashMap;
use std::marker::PhantomData;
use super::*;
use auth;
use error;

///Trait to generalize over paginated views of API results.
pub trait Cursor {
    ///What type is being returned by the API call?
    type Item;

    ///Returns a numeric reference to the previous page of results.
    fn previous_cursor_id(&self) -> i64;
    ///Returns a numeric reference to the next page of results.
    fn next_cursor_id(&self) -> i64;
    ///Consumes the cursor and returns the collection of results from inside.
    fn into_inner(self) -> Vec<Self::Item>;
}

///Represents a paginated list of results, such as the users who follow a specific user or the
///lists owned by that user.
///
///Implemented as an iterator that lazily loads a page of results at a time, but returns a single
///item per-iteration. See examples in [the user module-level documentation][user-mod].
///
///[user-mod]: user/index.html
#[must_use = "cursor iterators are lazy and do nothing unless consumed"]
pub struct CursorIter<'a, T>
    where T: Cursor + FromJson
{
    link: &'static str,
    con_token: &'a auth::Token<'a>,
    access_token: &'a auth::Token<'a>,
    user_id: Option<UserID<'a>>,
    ///The number of results returned in one network call.
    ///
    ///Certain calls set their own minimums and maximums for what this value can be. Furthermore,
    ///some calls don't allow you to set the size of the pages at all. Refer to the individual
    ///methods' documentation for specifics.
    pub page_size: Option<i32>,
    ///Numeric reference to the previous page of results.
    ///
    ///This value is intended to be automatically set and used as part of this struct's Iterator
    ///implementation. It is made available for those who wish to manually manage network calls and
    ///pagination.
    pub previous_cursor: i64,
    ///Numeric reference to the next page of results. A value of zero indicates that the current
    ///page of results is the last page of the cursor.
    ///
    ///This value is intended to be automatically set and used as part of this struct's Iterator
    ///implementation. It is made available for those who wish to manually manage network calls and
    ///pagination.
    pub next_cursor: i64,
    iter: Option<ResponseIter<T::Item>>,
    _marker: PhantomData<T>,
}

impl<'a, T> CursorIter<'a, T>
    where T: Cursor + FromJson
{
    ///Sets the number of results returned in a single network call.
    ///
    ///Certain calls set their own minimums and maximums for what this value can be. Furthermore,
    ///some calls don't allow you to set the size of the pages at all. Refer to the individual
    ///methods' documentation for specifics. If this method is called for a response that does not
    ///accept changing the page size, no change to the underlying struct will occur.
    ///
    ///Calling this function will invalidate any current results, if any were previously loaded.
    pub fn with_page_size(self, page_size: i32) -> CursorIter<'a, T> {
        if self.page_size.is_some() {
            CursorIter {
                link: self.link,
                con_token: self.con_token,
                access_token: self.access_token,
                user_id: self.user_id,
                page_size: Some(page_size),
                previous_cursor: -1,
                next_cursor: -1,
                iter: None,
                _marker: self._marker,
            }
        }
        else {
            self
        }
    }

    ///Loads the next page of results.
    ///
    ///This is intended to be used as part of this struct's Iterator implementation. It is provided
    ///as a convenience for those who wish to manage network calls and pagination manually.
    pub fn call(&self) -> Result<Response<T>, error::Error> {
        let mut params = HashMap::new();
        if let Some(ref id) = self.user_id {
            add_name_param(&mut params, id);
        }
        add_param(&mut params, "cursor", self.next_cursor.to_string());
        if let Some(count) = self.page_size {
            add_param(&mut params, "count", count.to_string());
        }

        let mut resp = try!(auth::get(self.link, self.con_token, self.access_token, Some(&params)));

        parse_response(&mut resp)
    }

    ///Creates a new instance of CursorIter, with the given parameters and empty initial results.
    pub fn new(link: &'static str, con_token: &'a auth::Token, access_token: &'a auth::Token,
               user_id: Option<UserID<'a>>, page_size: Option<i32>) -> CursorIter<'a, T> {
        CursorIter {
            link: link,
            con_token: con_token,
            access_token: access_token,
            user_id: user_id,
            page_size: page_size,
            previous_cursor: -1,
            next_cursor: -1,
            iter: None,
            _marker: PhantomData,
        }
    }
}

impl<'a, T> Iterator for CursorIter<'a, T>
    where T: Cursor + FromJson
{
    type Item = Result<Response<T::Item>, error::Error>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(ref mut results) = self.iter {
            if let Some(item) = results.next() {
                return Some(Ok(item));
            }
            else if self.next_cursor == 0 {
                return None;
            }
        }

        match self.call() {
            Ok(resp) => {
                self.previous_cursor = resp.response.previous_cursor_id();
                self.next_cursor = resp.response.next_cursor_id();

                let resp = Response {
                    rate_limit: resp.rate_limit,
                    rate_limit_remaining: resp.rate_limit_remaining,
                    rate_limit_reset: resp.rate_limit_reset,
                    response: resp.response.into_inner(),
                };

                let mut iter = resp.into_iter();
                let first = iter.next();
                self.iter = Some(iter);

                match first {
                    Some(item) => Some(Ok(item)),
                    None => None,
                }
            },
            Err(err) => Some(Err(err)),
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::path::Path;
use std::process::ExitStatus;

#[cfg(windows)]
pub fn open_with_default(file: &Path) -> io::Result<ExitStatus> {
    use std::mem;
    use std::os::windows::ffi::OsStrExt;
    use std::os::windows::process::ExitStatusExt;
    use std::ptr;
    use winapi::shared::minwindef::{DWORD, HKEY};
    use winapi::um::handleapi::CloseHandle;
    use winapi::um::processthreadsapi::GetExitCodeProcess;
    use winapi::um::shellapi::{ShellExecuteExW, SEE_MASK_NOCLOSEPROCESS, SHELLEXECUTEINFOW};
    use winapi::um::synchapi::WaitForSingleObject;
    use winapi::um::winbase::INFINITE;
    use winapi::um::winnt::HANDLE;
    use winapi::um::winuser::SW_SHOW;

    let file_name = file.as_os_str()
        .encode_wide()
        .chain(Some(0).into_iter())
        .collect::<Vec<_>>();

    let mut exec_info = SHELLEXECUTEINFOW {
        cbSize: mem::size_of::<SHELLEXECUTEINFOW>() as u32,
        fMask: SEE_MASK_NOCLOSEPROCESS,
        hwnd: ptr::null_mut(),
        lpVerb: ptr::null(),
        lpFile: file_name.as_ptr(),
        lpParameters: ptr::null(),
        lpDirectory: ptr::null(),
        nShow: SW_SHOW,
        hInstApp: ptr::null_mut(),
        lpIDList: ptr::null_mut(),
        lpClass: ptr::null(),
        hkeyClass: ptr::null_mut() as HKEY,
        dwHotKey: 0,
        hMonitor: ptr::null_mut() as HANDLE,
        hProcess: ptr::null_mut() as HANDLE,
    };

    unsafe {
        ShellExecuteExW(&mut exec_info);
        WaitForSingleObject(exec_info.hProcess, INFINITE);

        let mut exit_code = 0 as DWORD;
        GetExitCodeProcess(exec_info.hProcess, &mut exit_code);

        CloseHandle(exec_info.hProcess);

        Ok(ExitStatus::from_raw(exit_code as u32))
    }
}

#[cfg(not(windows))]
pub fn open_with_default(file: &Path) -> io::Result<ExitStatus> {
    use std::process::Command;

    let start_program = if cfg!(target_os = "linux") {
        "xdg-open"
    } else if cfg!(target_os = "macos") {
        "open"
    } else {
        unimplemented!();
    };

    let mut cmd = Command::new(start_program);
    cmd.arg(file);
    cmd.status()
}
<commit_msg>Capture process output (again) on non-Windows platforms<commit_after>use std::io;
use std::path::Path;
use std::process::ExitStatus;

#[cfg(windows)]
pub fn open_with_default(file: &Path) -> io::Result<ExitStatus> {
    use std::mem;
    use std::os::windows::ffi::OsStrExt;
    use std::os::windows::process::ExitStatusExt;
    use std::ptr;
    use winapi::shared::minwindef::{DWORD, HKEY};
    use winapi::um::handleapi::CloseHandle;
    use winapi::um::processthreadsapi::GetExitCodeProcess;
    use winapi::um::shellapi::{ShellExecuteExW, SEE_MASK_NOCLOSEPROCESS, SHELLEXECUTEINFOW};
    use winapi::um::synchapi::WaitForSingleObject;
    use winapi::um::winbase::INFINITE;
    use winapi::um::winnt::HANDLE;
    use winapi::um::winuser::SW_SHOW;

    let file_name = file.as_os_str()
        .encode_wide()
        .chain(Some(0).into_iter())
        .collect::<Vec<_>>();

    let mut exec_info = SHELLEXECUTEINFOW {
        cbSize: mem::size_of::<SHELLEXECUTEINFOW>() as u32,
        fMask: SEE_MASK_NOCLOSEPROCESS,
        hwnd: ptr::null_mut(),
        lpVerb: ptr::null(),
        lpFile: file_name.as_ptr(),
        lpParameters: ptr::null(),
        lpDirectory: ptr::null(),
        nShow: SW_SHOW,
        hInstApp: ptr::null_mut(),
        lpIDList: ptr::null_mut(),
        lpClass: ptr::null(),
        hkeyClass: ptr::null_mut() as HKEY,
        dwHotKey: 0,
        hMonitor: ptr::null_mut() as HANDLE,
        hProcess: ptr::null_mut() as HANDLE,
    };

    unsafe {
        ShellExecuteExW(&mut exec_info);
        WaitForSingleObject(exec_info.hProcess, INFINITE);

        let mut exit_code = 0 as DWORD;
        GetExitCodeProcess(exec_info.hProcess, &mut exit_code);

        CloseHandle(exec_info.hProcess);

        Ok(ExitStatus::from_raw(exit_code as u32))
    }
}

#[cfg(not(windows))]
pub fn open_with_default(file: &Path) -> io::Result<ExitStatus> {
    use std::process::Command;

    let start_program = if cfg!(target_os = "linux") {
        "xdg-open"
    } else if cfg!(target_os = "macos") {
        "open"
    } else {
        unimplemented!();
    };

    let mut cmd = Command::new(start_program);
    cmd.arg(file);
    cmd.output().map(|output| output.status)
}
<|endoftext|>


<commit_before>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use crate::raw_mutex::RawMutex;
use lock_api::{self, GetThreadId};

/// Implementation of the `GetThreadId` trait for `lock_api::ReentrantMutex`.
pub struct RawThreadId;

unsafe impl GetThreadId for RawThreadId {
    const INIT: RawThreadId = RawThreadId;

    fn nonzero_thread_id(&self) -> usize {
        // The address of a thread-local variable is guaranteed to be unique to the
        // current thread, and is also guaranteed to be non-zero.
        thread_local!(static KEY: u8 = unsafe { ::std::mem::uninitialized() });
        KEY.with(|x| x as *const _ as usize)
    }
}

/// A mutex which can be recursively locked by a single thread.
///
/// This type is identical to `Mutex` except for the following points:
///
/// - Locking multiple times from the same thread will work correctly instead of
///   deadlocking.
/// - `ReentrantMutexGuard` does not give mutable references to the locked data.
///   Use a `RefCell` if you need this.
///
/// See [`Mutex`](struct.Mutex.html) for more details about the underlying mutex
/// primitive.
pub type ReentrantMutex<T> = lock_api::ReentrantMutex<RawMutex, RawThreadId, T>;

/// An RAII implementation of a "scoped lock" of a reentrant mutex. When this structure
/// is dropped (falls out of scope), the lock will be unlocked.
///
/// The data protected by the mutex can be accessed through this guard via its
/// `Deref` implementation.
pub type ReentrantMutexGuard<'a, T> = lock_api::ReentrantMutexGuard<'a, RawMutex, RawThreadId, T>;

/// An RAII mutex guard returned by `ReentrantMutexGuard::map`, which can point to a
/// subfield of the protected data.
///
/// The main difference between `MappedReentrantMutexGuard` and `ReentrantMutexGuard` is that the
/// former doesn't support temporarily unlocking and re-locking, since that
/// could introduce soundness issues if the locked object is modified by another
/// thread.
pub type MappedReentrantMutexGuard<'a, T> =
    lock_api::MappedReentrantMutexGuard<'a, RawMutex, RawThreadId, T>;

#[cfg(test)]
mod tests {
    use crate::ReentrantMutex;
    use std::cell::RefCell;
    use std::sync::Arc;
    use std::thread;

    #[test]
    fn smoke() {
        let m = ReentrantMutex::new(());
        {
            let a = m.lock();
            {
                let b = m.lock();
                {
                    let c = m.lock();
                    assert_eq!(*c, ());
                }
                assert_eq!(*b, ());
            }
            assert_eq!(*a, ());
        }
    }

    #[test]
    fn is_mutex() {
        let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
        let m2 = m.clone();
        let lock = m.lock();
        let child = thread::spawn(move || {
            let lock = m2.lock();
            assert_eq!(*lock.borrow(), 4950);
        });
        for i in 0..100 {
            let lock = m.lock();
            *lock.borrow_mut() += i;
        }
        drop(lock);
        child.join().unwrap();
    }

    #[test]
    fn trylock_works() {
        let m = Arc::new(ReentrantMutex::new(()));
        let m2 = m.clone();
        let _lock = m.try_lock();
        let _lock2 = m.try_lock();
        thread::spawn(move || {
            let lock = m2.try_lock();
            assert!(lock.is_none());
        })
        .join()
        .unwrap();
        let _lock3 = m.try_lock();
    }

    #[test]
    fn test_reentrant_mutex_debug() {
        let mutex = ReentrantMutex::new(vec![0u8, 10]);

        assert_eq!(format!("{:?}", mutex), "ReentrantMutex { data: [0, 10] }");
    }
}
<commit_msg>Added serde support to remutex::RawThreadId<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use crate::raw_mutex::RawMutex;
use lock_api::{self, GetThreadId};

#[cfg(feature = "enable_serde")]
extern crate serde;
#[cfg(feature = "enable_serde")]
use self::serde::*;

/// Implementation of the `GetThreadId` trait for `lock_api::ReentrantMutex`.
#[cfg_attr(feature = "enable_serde", derive(Serialize, Deserialize))]
pub struct RawThreadId;

unsafe impl GetThreadId for RawThreadId {
    const INIT: RawThreadId = RawThreadId;

    fn nonzero_thread_id(&self) -> usize {
        // The address of a thread-local variable is guaranteed to be unique to the
        // current thread, and is also guaranteed to be non-zero.
        thread_local!(static KEY: u8 = unsafe { ::std::mem::uninitialized() });
        KEY.with(|x| x as *const _ as usize)
    }
}

/// A mutex which can be recursively locked by a single thread.
///
/// This type is identical to `Mutex` except for the following points:
///
/// - Locking multiple times from the same thread will work correctly instead of
///   deadlocking.
/// - `ReentrantMutexGuard` does not give mutable references to the locked data.
///   Use a `RefCell` if you need this.
///
/// See [`Mutex`](struct.Mutex.html) for more details about the underlying mutex
/// primitive.
pub type ReentrantMutex<T> = lock_api::ReentrantMutex<RawMutex, RawThreadId, T>;

/// An RAII implementation of a "scoped lock" of a reentrant mutex. When this structure
/// is dropped (falls out of scope), the lock will be unlocked.
///
/// The data protected by the mutex can be accessed through this guard via its
/// `Deref` implementation.
pub type ReentrantMutexGuard<'a, T> = lock_api::ReentrantMutexGuard<'a, RawMutex, RawThreadId, T>;

/// An RAII mutex guard returned by `ReentrantMutexGuard::map`, which can point to a
/// subfield of the protected data.
///
/// The main difference between `MappedReentrantMutexGuard` and `ReentrantMutexGuard` is that the
/// former doesn't support temporarily unlocking and re-locking, since that
/// could introduce soundness issues if the locked object is modified by another
/// thread.
pub type MappedReentrantMutexGuard<'a, T> =
    lock_api::MappedReentrantMutexGuard<'a, RawMutex, RawThreadId, T>;

#[cfg(test)]
mod tests {
    use crate::ReentrantMutex;
    use std::cell::RefCell;
    use std::sync::Arc;
    use std::thread;

    #[test]
    fn smoke() {
        let m = ReentrantMutex::new(());
        {
            let a = m.lock();
            {
                let b = m.lock();
                {
                    let c = m.lock();
                    assert_eq!(*c, ());
                }
                assert_eq!(*b, ());
            }
            assert_eq!(*a, ());
        }
    }

    #[test]
    fn is_mutex() {
        let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
        let m2 = m.clone();
        let lock = m.lock();
        let child = thread::spawn(move || {
            let lock = m2.lock();
            assert_eq!(*lock.borrow(), 4950);
        });
        for i in 0..100 {
            let lock = m.lock();
            *lock.borrow_mut() += i;
        }
        drop(lock);
        child.join().unwrap();
    }

    #[test]
    fn trylock_works() {
        let m = Arc::new(ReentrantMutex::new(()));
        let m2 = m.clone();
        let _lock = m.try_lock();
        let _lock2 = m.try_lock();
        thread::spawn(move || {
            let lock = m2.try_lock();
            assert!(lock.is_none());
        })
        .join()
        .unwrap();
        let _lock3 = m.try_lock();
    }

    #[test]
    fn test_reentrant_mutex_debug() {
        let mutex = ReentrantMutex::new(vec![0u8, 10]);

        assert_eq!(format!("{:?}", mutex), "ReentrantMutex { data: [0, 10] }");
    }
}
<|endoftext|>