<commit_before>use gfx;
use gfx::traits::FactoryExt;
use core::resource;

extern crate cgmath;
extern crate gfx_text;

gfx_vertex_struct!(VertexPosNormal {
	pos: [f32; 3] = "a_Pos",
	normal: [f32; 3] = "a_Normal",
	tangent: [f32; 3] = "a_Tangent",
	tex_coord: [f32; 2] = "a_TexCoord",
});

impl Default for VertexPosNormal {
	fn default() -> Self {
		VertexPosNormal {
			pos: [0.; 3],
			normal: [0., 0., 1.],
			tangent: [1., 0., 0.],
			tex_coord: [0.5, 0.5],
		}
	}
}

pub type Vertex = VertexPosNormal;
pub type HDRColorFormat = (gfx::format::R16_G16_B16_A16, gfx::format::Float);
pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

const MAX_NUM_TOTAL_LIGHTS: usize = 16;

pub type GFormat = [f32; 4];

pub type M44 = cgmath::Matrix4<f32>;

gfx_defines!(
    constant PointLight {
        propagation: [f32; 4] = "propagation",
        center: [f32; 4] = "center",
        color: [f32; 4] = "color",
    }

    constant CameraArgs {
        proj: [[f32; 4]; 4] = "u_Proj",
        view: [[f32; 4]; 4] = "u_View",
    }

    constant ModelArgs {
        model: [[f32; 4]; 4] = "u_Model",
    }

    constant FragmentArgs {
        light_count: i32 = "u_LightCount",
    }

	constant MaterialArgs {
		emissive: [f32; 4] = "u_Emissive",
	}

    pipeline shaded {
        vbuf: gfx::VertexBuffer<VertexPosNormal> = (),
        camera_args: gfx::ConstantBuffer<CameraArgs> = "cb_CameraArgs",
        model_args: gfx::ConstantBuffer<ModelArgs> = "cb_ModelArgs",
        fragment_args: gfx::ConstantBuffer<FragmentArgs> = "cb_FragmentArgs",
        material_args: gfx::ConstantBuffer<MaterialArgs> = "cb_MaterialArgs",
        lights: gfx::ConstantBuffer<PointLight> = "u_Lights",
        color_target: gfx::RenderTarget<HDRColorFormat> = "o_Color",
        depth_target: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
    }
);

use std::marker::PhantomData;

pub enum Shader {
	Ball = 0,
	Flat = 1,
	Wireframe = 2,
	Lines = 3,
	Count = 4,
}

pub struct ForwardLighting<R: gfx::Resources, C: gfx::CommandBuffer<R>> {
	camera: gfx::handle::Buffer<R, CameraArgs>,
	model: gfx::handle::Buffer<R, ModelArgs>,
	fragment: gfx::handle::Buffer<R, FragmentArgs>,
	material: gfx::handle::Buffer<R, MaterialArgs>,
	lights: gfx::handle::Buffer<R, PointLight>,
	pso: [gfx::pso::PipelineState<R, shaded::Meta>; Shader::Count as usize],
	_buffer: PhantomData<C>,
}

impl<R: gfx::Resources, C: gfx::CommandBuffer<R>> ForwardLighting<R, C> {
	pub fn new<F>(factory: &mut F, res: &resource::ResourceLoader<u8>) -> ForwardLighting<R, C>
		where F: gfx::Factory<R> {
		let lights = factory.create_constant_buffer(MAX_NUM_TOTAL_LIGHTS);
		let camera = factory.create_constant_buffer(1);
		let model = factory.create_constant_buffer(1);
		let fragment = factory.create_constant_buffer(1);
		let material = factory.create_constant_buffer(1);

		macro_rules! load_shaders {
			($v:expr, $f:expr) => { factory.create_shader_set(
					&res.load(concat!("shaders/forward/", $v, ".vert")).unwrap(),
					&res.load(concat!("shaders/forward/", $f, ".frag")).unwrap())
				.unwrap() }
		};

		let solid_shaders = load_shaders!("lighting", "lighting_poly");
		let ball_shaders = load_shaders!("lighting", "lighting_ball");

		let solid_rasterizer = gfx::state::Rasterizer {
			samples: Some(gfx::state::MultiSample),
			..gfx::state::Rasterizer::new_fill()
		};

		let line_rasterizer = gfx::state::Rasterizer { method: gfx::state::RasterMethod::Line(2), ..solid_rasterizer };

		let ball_pso = Self::new_pso(factory,
		                             &ball_shaders,
		                             gfx::Primitive::TriangleList,
		                             solid_rasterizer);
		let poly_pso = Self::new_pso(factory,
		                             &solid_shaders,
		                             gfx::Primitive::TriangleList,
		                             solid_rasterizer);
		let wireframe_pso = Self::new_pso(factory,
		                                  &solid_shaders,
		                                  gfx::Primitive::TriangleList,
		                                  line_rasterizer);
		let lines_pso = Self::new_pso(factory,
		                              &solid_shaders,
		                              gfx::Primitive::LineStrip,
		                              line_rasterizer);
		ForwardLighting {
			camera: camera,
			model: model,
			fragment: fragment,
			material: material,
			lights: lights,
			pso: [ball_pso, poly_pso, wireframe_pso, lines_pso],
			_buffer: PhantomData,
		}
	}

	fn new_pso<F>(factory: &mut F,
	              shaders: &gfx::ShaderSet<R>,
	              primitive: gfx::Primitive,
	              rasterizer: gfx::state::Rasterizer)
	              -> gfx::pso::PipelineState<R, shaded::Meta>
		where F: gfx::Factory<R> {
		factory.create_pipeline_state(&shaders, primitive, rasterizer, shaded::new())
		       .unwrap()
	}

	pub fn setup(&self,
	             encoder: &mut gfx::Encoder<R, C>,
	             camera_projection: M44,
	             camera_view: M44,
	             lights: &Vec<PointLight>) {

		let mut lights_buf = lights.clone();

		let count = lights_buf.len();
		while lights_buf.len() < MAX_NUM_TOTAL_LIGHTS {
			lights_buf.push(PointLight {
				propagation: [0., 0., 0., 0.],
				color: [0., 0., 0., 0.],
				center: [0., 0., 0., 0.],
			})
		}

		encoder.update_buffer(&self.lights, &lights_buf[..], 0).unwrap();
		encoder.update_constant_buffer(&self.camera,
		                               &CameraArgs {
			                               proj: camera_projection.into(),
			                               view: camera_view.into(),
		                               });
		encoder.update_constant_buffer(&self.fragment, &FragmentArgs { light_count: count as i32 });
	}

	pub fn draw_primitives(&self,
	                      shader: Shader,
	                      encoder: &mut gfx::Encoder<R, C>,
	                      vertices: gfx::handle::Buffer<R, VertexPosNormal>,
	                      indices: &gfx::Slice<R>,
	                      transform: &M44,
	                      color: [f32; 4],
	                      color_buffer: &gfx::handle::RenderTargetView<R, HDRColorFormat>,
	                      depth_buffer: &gfx::handle::DepthStencilView<R, DepthFormat>) {
		encoder.update_constant_buffer(&self.model, &ModelArgs { model: (*transform).into() });
		encoder.update_constant_buffer(&self.material, &MaterialArgs { emissive: color });
		encoder.draw(indices,
		             &self.pso[shader as usize],
		             &shaded::Data {
			             vbuf: vertices,
			             fragment_args: self.fragment.clone(),
			             material_args: self.material.clone(),
			             camera_args: self.camera.clone(),
			             model_args: self.model.clone(),
			             lights: self.lights.clone(),
			             color_target: color_buffer.clone(),
			             depth_target: depth_buffer.clone(),
		             });
	}
}
<commit_msg>Enabled Alpha blending<commit_after>use gfx;
use gfx::traits::FactoryExt;
use core::resource;

extern crate cgmath;
extern crate gfx_text;

gfx_vertex_struct!(VertexPosNormal {
	pos: [f32; 3] = "a_Pos",
	normal: [f32; 3] = "a_Normal",
	tangent: [f32; 3] = "a_Tangent",
	tex_coord: [f32; 2] = "a_TexCoord",
});

impl Default for VertexPosNormal {
	fn default() -> Self {
		VertexPosNormal {
			pos: [0.; 3],
			normal: [0., 0., 1.],
			tangent: [1., 0., 0.],
			tex_coord: [0.5, 0.5],
		}
	}
}

pub type Vertex = VertexPosNormal;
pub type HDRColorFormat = (gfx::format::R16_G16_B16_A16, gfx::format::Float);
pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

const MAX_NUM_TOTAL_LIGHTS: usize = 16;

pub type GFormat = [f32; 4];

pub type M44 = cgmath::Matrix4<f32>;

gfx_defines!(
    constant PointLight {
        propagation: [f32; 4] = "propagation",
        center: [f32; 4] = "center",
        color: [f32; 4] = "color",
    }

    constant CameraArgs {
        proj: [[f32; 4]; 4] = "u_Proj",
        view: [[f32; 4]; 4] = "u_View",
    }

    constant ModelArgs {
        model: [[f32; 4]; 4] = "u_Model",
    }

    constant FragmentArgs {
        light_count: i32 = "u_LightCount",
    }

	constant MaterialArgs {
		emissive: [f32; 4] = "u_Emissive",
	}

    pipeline shaded {
        vbuf: gfx::VertexBuffer<VertexPosNormal> = (),
        camera_args: gfx::ConstantBuffer<CameraArgs> = "cb_CameraArgs",
        model_args: gfx::ConstantBuffer<ModelArgs> = "cb_ModelArgs",
        fragment_args: gfx::ConstantBuffer<FragmentArgs> = "cb_FragmentArgs",
        material_args: gfx::ConstantBuffer<MaterialArgs> = "cb_MaterialArgs",
        lights: gfx::ConstantBuffer<PointLight> = "u_Lights",
        color_target: gfx::BlendTarget<HDRColorFormat> = ("o_Color", gfx::state::MASK_ALL, gfx::preset::blend::ADD),
        depth_target: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
    }
);

use std::marker::PhantomData;

pub enum Shader {
	Ball = 0,
	Flat = 1,
	Wireframe = 2,
	Lines = 3,
	Count = 4,
}

pub struct ForwardLighting<R: gfx::Resources, C: gfx::CommandBuffer<R>> {
	camera: gfx::handle::Buffer<R, CameraArgs>,
	model: gfx::handle::Buffer<R, ModelArgs>,
	fragment: gfx::handle::Buffer<R, FragmentArgs>,
	material: gfx::handle::Buffer<R, MaterialArgs>,
	lights: gfx::handle::Buffer<R, PointLight>,
	pso: [gfx::pso::PipelineState<R, shaded::Meta>; Shader::Count as usize],
	_buffer: PhantomData<C>,
}

impl<R: gfx::Resources, C: gfx::CommandBuffer<R>> ForwardLighting<R, C> {
	pub fn new<F>(factory: &mut F, res: &resource::ResourceLoader<u8>) -> ForwardLighting<R, C>
		where F: gfx::Factory<R> {
		let lights = factory.create_constant_buffer(MAX_NUM_TOTAL_LIGHTS);
		let camera = factory.create_constant_buffer(1);
		let model = factory.create_constant_buffer(1);
		let fragment = factory.create_constant_buffer(1);
		let material = factory.create_constant_buffer(1);

		macro_rules! load_shaders {
			($v:expr, $f:expr) => { factory.create_shader_set(
					&res.load(concat!("shaders/forward/", $v, ".vert")).unwrap(),
					&res.load(concat!("shaders/forward/", $f, ".frag")).unwrap())
				.unwrap() }
		};

		let solid_shaders = load_shaders!("lighting", "lighting_poly");
		let ball_shaders = load_shaders!("lighting", "lighting_ball");

		let solid_rasterizer = gfx::state::Rasterizer {
			samples: Some(gfx::state::MultiSample),
			..gfx::state::Rasterizer::new_fill()
		};

		let line_rasterizer = gfx::state::Rasterizer { method: gfx::state::RasterMethod::Line(2), ..solid_rasterizer };

		let ball_pso = Self::new_pso(factory,
		                             &ball_shaders,
		                             gfx::Primitive::TriangleList,
		                             solid_rasterizer);
		let poly_pso = Self::new_pso(factory,
		                             &solid_shaders,
		                             gfx::Primitive::TriangleList,
		                             solid_rasterizer);
		let wireframe_pso = Self::new_pso(factory,
		                                  &solid_shaders,
		                                  gfx::Primitive::TriangleList,
		                                  line_rasterizer);
		let lines_pso = Self::new_pso(factory,
		                              &solid_shaders,
		                              gfx::Primitive::LineStrip,
		                              line_rasterizer);
		ForwardLighting {
			camera: camera,
			model: model,
			fragment: fragment,
			material: material,
			lights: lights,
			pso: [ball_pso, poly_pso, wireframe_pso, lines_pso],
			_buffer: PhantomData,
		}
	}

	fn new_pso<F>(factory: &mut F,
	              shaders: &gfx::ShaderSet<R>,
	              primitive: gfx::Primitive,
	              rasterizer: gfx::state::Rasterizer)
	              -> gfx::pso::PipelineState<R, shaded::Meta>
		where F: gfx::Factory<R> {
		factory.create_pipeline_state(&shaders, primitive, rasterizer, shaded::new())
		       .unwrap()
	}

	pub fn setup(&self,
	             encoder: &mut gfx::Encoder<R, C>,
	             camera_projection: M44,
	             camera_view: M44,
	             lights: &Vec<PointLight>) {

		let mut lights_buf = lights.clone();

		let count = lights_buf.len();
		while lights_buf.len() < MAX_NUM_TOTAL_LIGHTS {
			lights_buf.push(PointLight {
				propagation: [0., 0., 0., 0.],
				color: [0., 0., 0., 0.],
				center: [0., 0., 0., 0.],
			})
		}

		encoder.update_buffer(&self.lights, &lights_buf[..], 0).unwrap();
		encoder.update_constant_buffer(&self.camera,
		                               &CameraArgs {
			                               proj: camera_projection.into(),
			                               view: camera_view.into(),
		                               });
		encoder.update_constant_buffer(&self.fragment, &FragmentArgs { light_count: count as i32 });
	}

	pub fn draw_primitives(&self,
	                      shader: Shader,
	                      encoder: &mut gfx::Encoder<R, C>,
	                      vertices: gfx::handle::Buffer<R, VertexPosNormal>,
	                      indices: &gfx::Slice<R>,
	                      transform: &M44,
	                      color: [f32; 4],
	                      color_buffer: &gfx::handle::RenderTargetView<R, HDRColorFormat>,
	                      depth_buffer: &gfx::handle::DepthStencilView<R, DepthFormat>) {
		encoder.update_constant_buffer(&self.model, &ModelArgs { model: (*transform).into() });
		encoder.update_constant_buffer(&self.material, &MaterialArgs { emissive: color });
		encoder.draw(indices,
		             &self.pso[shader as usize],
		             &shaded::Data {
			             vbuf: vertices,
			             fragment_args: self.fragment.clone(),
			             material_args: self.material.clone(),
			             camera_args: self.camera.clone(),
			             model_args: self.model.clone(),
			             lights: self.lights.clone(),
			             color_target: color_buffer.clone(),
			             depth_target: depth_buffer.clone(),
		             });
	}
}
<|endoftext|>


<commit_before>extern crate syntex_syntax;

use std::fs::File;
use std::io;
use std::path::Path;

use syntex_syntax::ast;
use syntex_syntax::attr;
use syntex_syntax::codemap::{DUMMY_SP, respan};
use syntex_syntax::ext::base::{
    IdentMacroExpander,
    MultiItemDecorator,
    MultiItemModifier,
    NamedSyntaxExtension,
    SyntaxExtension,
    TTMacroExpander,
};
use syntex_syntax::ext::base::ExtCtxt;
use syntex_syntax::ext::expand;
use syntex_syntax::feature_gate;
use syntex_syntax::parse::{self, token};
use syntex_syntax::print::{pp, pprust};
use syntex_syntax::ptr::P;

pub type Pass = fn(ast::Crate) -> ast::Crate;

pub struct Registry {
    macros: Vec<ast::MacroDef>,
    syntax_exts: Vec<NamedSyntaxExtension>,
    pre_expansion_passes: Vec<Box<Pass>>,
    post_expansion_passes: Vec<Box<Pass>>,
    cfg: Vec<P<ast::MetaItem>>,
    attrs: Vec<ast::Attribute>,
}

impl Registry {
    pub fn new() -> Registry {
        Registry {
            macros: Vec::new(),
            syntax_exts: Vec::new(),
            pre_expansion_passes: Vec::new(),
            post_expansion_passes: Vec::new(),
            cfg: Vec::new(),
            attrs: Vec::new(),
        }
    }

    pub fn add_cfg(&mut self, cfg: &str) {
        let meta_item = parse::parse_meta_from_source_str(
            "cfgspec".to_string(),
            cfg.to_string(),
            Vec::new(),
            &parse::ParseSess::new());

        self.cfg.push(meta_item);
    }

    pub fn add_attr(&mut self, attr: &str) {
        let meta_item = parse::parse_meta_from_source_str(
            "attrspec".to_string(),
            attr.to_string(),
            Vec::new(),
            &parse::ParseSess::new());

        self.attrs.push(respan(DUMMY_SP, ast::Attribute_ {
            id: attr::mk_attr_id(),
            style: ast::AttrStyle::Outer,
            value: meta_item,
            is_sugared_doc: false,
        }));
    }

    pub fn add_macro<F>(&mut self, name: &str, extension: F)
        where F: TTMacroExpander + 'static
    {
        let name = token::intern(name);
        let syntax_extension = SyntaxExtension::NormalTT(
            Box::new(extension),
            None,
            false
        );
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_ident_macro<F>(&mut self, name: &str, extension: F)
        where F: IdentMacroExpander + 'static
    {
        let name = token::intern(name);
        let syntax_extension = SyntaxExtension::IdentTT(
            Box::new(extension),
            None,
            false
        );
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_decorator<F>(&mut self, name: &str, extension: F)
        where F: MultiItemDecorator + 'static
    {
        let name = token::intern(name);
        let syntax_extension = SyntaxExtension::MultiDecorator(Box::new(extension));
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_modifier<F>(&mut self, name: &str, extension: F)
        where F: MultiItemModifier + 'static
    {
        let name = token::intern(name);
        let syntax_extension = SyntaxExtension::MultiModifier(Box::new(extension));
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_pre_expansion_pass(&mut self, pass: Pass) {
        self.pre_expansion_passes.push(Box::new(pass))
    }

    pub fn add_post_expansion_pass(&mut self, pass: Pass) {
        self.post_expansion_passes.push(Box::new(pass))
    }

    pub fn expand(self, crate_name: &str, src: &Path, dst: &Path) -> io::Result<()> {
        let sess = parse::ParseSess::new();

        let mut krate = parse::parse_crate_from_file(
            src,
            self.cfg,
            &sess);

        krate.attrs.extend(self.attrs);

        let features = feature_gate::check_crate_macros(
            &sess.codemap(),
            &sess.span_diagnostic,
            &krate);

        let krate = self.pre_expansion_passes.iter()
            .fold(krate, |krate, f| (f)(krate));

        let mut ecfg = expand::ExpansionConfig::default(crate_name.to_string());
        ecfg.features = Some(&features);

        let cfg = Vec::new();
        let mut gated_cfgs = Vec::new();
        let ecx = ExtCtxt::new(&sess, cfg, ecfg, &mut gated_cfgs);

        let (krate, _) = expand::expand_crate(ecx, self.macros, self.syntax_exts, krate);

        let krate = self.post_expansion_passes.iter()
            .fold(krate, |krate, f| (f)(krate));

        let dst = try!(File::create(dst));

        let mut printer = pprust::rust_printer(Box::new(dst));
        try!(printer.print_mod(&krate.module, &krate.attrs[..]));
        try!(printer.print_remaining_comments());
        pp::eof(&mut printer.s)
    }
}
<commit_msg>fix(syntex): Use pprust::print_crate to write crate<commit_after>extern crate syntex_syntax;

use std::fs::File;
use std::io::{self, Write};
use std::path::Path;

use syntex_syntax::ast;
use syntex_syntax::attr;
use syntex_syntax::codemap::{DUMMY_SP, respan};
use syntex_syntax::ext::base::{
    IdentMacroExpander,
    MultiItemDecorator,
    MultiItemModifier,
    NamedSyntaxExtension,
    SyntaxExtension,
    TTMacroExpander,
};
use syntex_syntax::ext::base::ExtCtxt;
use syntex_syntax::ext::expand;
use syntex_syntax::feature_gate;
use syntex_syntax::parse::{self, token};
use syntex_syntax::print::pprust;
use syntex_syntax::ptr::P;

pub type Pass = fn(ast::Crate) -> ast::Crate;

pub struct Registry {
    macros: Vec<ast::MacroDef>,
    syntax_exts: Vec<NamedSyntaxExtension>,
    pre_expansion_passes: Vec<Box<Pass>>,
    post_expansion_passes: Vec<Box<Pass>>,
    cfg: Vec<P<ast::MetaItem>>,
    attrs: Vec<ast::Attribute>,
}

impl Registry {
    pub fn new() -> Registry {
        Registry {
            macros: Vec::new(),
            syntax_exts: Vec::new(),
            pre_expansion_passes: Vec::new(),
            post_expansion_passes: Vec::new(),
            cfg: Vec::new(),
            attrs: Vec::new(),
        }
    }

    pub fn add_cfg(&mut self, cfg: &str) {
        let meta_item = parse::parse_meta_from_source_str(
            "cfgspec".to_string(),
            cfg.to_string(),
            Vec::new(),
            &parse::ParseSess::new());

        self.cfg.push(meta_item);
    }

    pub fn add_attr(&mut self, attr: &str) {
        let meta_item = parse::parse_meta_from_source_str(
            "attrspec".to_string(),
            attr.to_string(),
            Vec::new(),
            &parse::ParseSess::new());

        self.attrs.push(respan(DUMMY_SP, ast::Attribute_ {
            id: attr::mk_attr_id(),
            style: ast::AttrStyle::Outer,
            value: meta_item,
            is_sugared_doc: false,
        }));
    }

    pub fn add_macro<F>(&mut self, name: &str, extension: F)
        where F: TTMacroExpander + 'static
    {
        let name = token::intern(name);
        let syntax_extension = SyntaxExtension::NormalTT(
            Box::new(extension),
            None,
            false
        );
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_ident_macro<F>(&mut self, name: &str, extension: F)
        where F: IdentMacroExpander + 'static
    {
        let name = token::intern(name);
        let syntax_extension = SyntaxExtension::IdentTT(
            Box::new(extension),
            None,
            false
        );
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_decorator<F>(&mut self, name: &str, extension: F)
        where F: MultiItemDecorator + 'static
    {
        let name = token::intern(name);
        let syntax_extension = SyntaxExtension::MultiDecorator(Box::new(extension));
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_modifier<F>(&mut self, name: &str, extension: F)
        where F: MultiItemModifier + 'static
    {
        let name = token::intern(name);
        let syntax_extension = SyntaxExtension::MultiModifier(Box::new(extension));
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_pre_expansion_pass(&mut self, pass: Pass) {
        self.pre_expansion_passes.push(Box::new(pass))
    }

    pub fn add_post_expansion_pass(&mut self, pass: Pass) {
        self.post_expansion_passes.push(Box::new(pass))
    }

    pub fn expand(self, crate_name: &str, src: &Path, dst: &Path) -> io::Result<()> {
        let sess = parse::ParseSess::new();

        let mut krate = parse::parse_crate_from_file(
            src,
            self.cfg,
            &sess);

        krate.attrs.extend(self.attrs);

        let features = feature_gate::check_crate_macros(
            &sess.codemap(),
            &sess.span_diagnostic,
            &krate);

        let krate = self.pre_expansion_passes.iter()
            .fold(krate, |krate, f| (f)(krate));

        let mut ecfg = expand::ExpansionConfig::default(crate_name.to_string());
        ecfg.features = Some(&features);

        let cfg = Vec::new();
        let mut gated_cfgs = Vec::new();
        let ecx = ExtCtxt::new(&sess, cfg, ecfg, &mut gated_cfgs);

        let (krate, _) = expand::expand_crate(ecx, self.macros, self.syntax_exts, krate);

        let krate = self.post_expansion_passes.iter()
            .fold(krate, |krate, f| (f)(krate));

        let src_name = src.to_str().unwrap().to_string();
        let src = sess.codemap()
            .get_filemap(&src_name)
            .src
            .as_ref()
            .unwrap()
            .as_bytes()
            .to_vec();
        let mut rdr = &src[..];

        let mut out = Vec::new();
        let annotation = pprust::NoAnn;

        {
            let out: &mut io::Write = &mut out;

            try!(pprust::print_crate(
                sess.codemap(),
                &sess.span_diagnostic,
                &krate,
                src_name.to_string(),
                &mut rdr,
                Box::new(out),
                &annotation,
                false)
            );
        }

        let mut dst = try!(File::create(dst));
        dst.write_all(&out)
    }
}
<|endoftext|>


<commit_before>use std::error::Error as StdError;
use std::str::FromStr;
use std::time::Duration;
use std::{env, fmt};

use dotenv::dotenv;
use serenity::async_trait;
use serenity::builder::{CreateActionRow, CreateButton, CreateSelectMenu, CreateSelectMenuOption};
use serenity::client::{Context, EventHandler};
use serenity::futures::StreamExt;
use serenity::model::application::component::ButtonStyle;
use serenity::model::application::interaction::InteractionResponseType;
use serenity::model::channel::Message;
use serenity::prelude::*;

#[derive(Debug)]
enum Animal {
    Cat,
    Dog,
    Horse,
    Alpaca,
}

#[derive(Debug)]
struct ParseComponentError(String);

impl fmt::Display for ParseComponentError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Failed to parse {} as component", self.0)
    }
}

impl StdError for ParseComponentError {}

impl fmt::Display for Animal {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Cat => write!(f, "Cat"),
            Self::Dog => write!(f, "Dog"),
            Self::Horse => write!(f, "Horse"),
            Self::Alpaca => write!(f, "Alpaca"),
        }
    }
}

impl FromStr for Animal {
    type Err = ParseComponentError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "cat" => Ok(Animal::Cat),
            "dog" => Ok(Animal::Dog),
            "horse" => Ok(Animal::Horse),
            "alpaca" => Ok(Animal::Alpaca),
            _ => Err(ParseComponentError(s.to_string())),
        }
    }
}

impl Animal {
    fn emoji(&self) -> char {
        match self {
            Self::Cat => '🐈',
            Self::Dog => '🐕',
            Self::Horse => '🐎',
            Self::Alpaca => '🦙',
        }
    }

    fn menu_option(&self) -> CreateSelectMenuOption {
        let mut opt = CreateSelectMenuOption::default();
        // This is what will be shown to the user
        opt.label(format!("{} {}", self.emoji(), self));
        // This is used to identify the selected value
        opt.value(self.to_string().to_ascii_lowercase());
        opt
    }

    fn select_menu() -> CreateSelectMenu {
        let mut menu = CreateSelectMenu::default();
        menu.custom_id("animal_select");
        menu.placeholder("No animal selected");
        menu.options(|f| {
            f.add_option(Self::Cat.menu_option())
                .add_option(Self::Dog.menu_option())
                .add_option(Self::Horse.menu_option())
                .add_option(Self::Alpaca.menu_option())
        });
        menu
    }

    fn action_row() -> CreateActionRow {
        let mut ar = CreateActionRow::default();
        // A select menu must be the only thing in an action row!
        ar.add_select_menu(Self::select_menu());
        ar
    }
}

#[derive(Debug)]
enum Sound {
    Meow,
    Woof,
    Neigh,
    Honk,
}

impl fmt::Display for Sound {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Meow => write!(f, "meow"),
            Self::Woof => write!(f, "woof"),
            Self::Neigh => write!(f, "neigh"),
            Self::Honk => write!(f, "hoooooooonk"),
        }
    }
}

impl Sound {
    fn emoji(&self) -> char {
        match self {
            Self::Meow => Animal::Cat.emoji(),
            Self::Woof => Animal::Dog.emoji(),
            Self::Neigh => Animal::Horse.emoji(),
            Self::Honk => Animal::Alpaca.emoji(),
        }
    }

    fn button(&self) -> CreateButton {
        let mut b = CreateButton::default();
        b.custom_id(self.to_string().to_ascii_lowercase());
        b.emoji(self.emoji());
        b.label(self);
        b.style(ButtonStyle::Primary);
        b
    }

    fn action_row() -> CreateActionRow {
        let mut ar = CreateActionRow::default();
        // We can add up to 5 buttons per action row
        ar.add_button(Sound::Meow.button());
        ar.add_button(Sound::Woof.button());
        ar.add_button(Sound::Neigh.button());
        ar.add_button(Sound::Honk.button());
        ar
    }
}

impl FromStr for Sound {
    type Err = ParseComponentError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "meow" => Ok(Sound::Meow),
            "woof" => Ok(Sound::Woof),
            "neigh" => Ok(Sound::Neigh),
            "hoooooooonk" => Ok(Sound::Honk),
            _ => Err(ParseComponentError(s.to_string())),
        }
    }
}

struct Handler;

#[async_trait]
impl EventHandler for Handler {
    async fn message(&self, ctx: Context, msg: Message) {
        if msg.content != "animal" {
            return;
        }

        // Ask the user for its favorite animal
        let m = msg
            .channel_id
            .send_message(&ctx, |m| {
                m.content("Please select your favorite animal")
                    .components(|c| c.add_action_row(Animal::action_row()))
            })
            .await
            .unwrap();

        // Wait for the user to make a selection
        let mci =
            match m.await_component_interaction(&ctx).timeout(Duration::from_secs(60 * 3)).await {
                Some(ci) => ci,
                None => {
                    m.reply(&ctx, "Timed out").await.unwrap();
                    return;
                },
            };

        // data.custom_id contains the id of the component (here "animal_select")
        // and should be used to identify if a message has multiple components.
        // data.values contains the selected values from the menu
        let animal = Animal::from_str(mci.data.values.get(0).unwrap()).unwrap();

        // Acknowledge the interaction and edit the message
        mci.create_interaction_response(&ctx, |r| {
            r.kind(InteractionResponseType::UpdateMessage).interaction_response_data(|d| {
                d.content(format!("You chose: **{}**\nNow choose a sound!", animal))
                    .components(|c| c.add_action_row(Sound::action_row()))
            })
        })
        .await
        .unwrap();

        // Wait for multiple interactions

        let mut cib =
            m.await_component_interactions(&ctx).timeout(Duration::from_secs(60 * 3)).build();

        while let Some(mci) = cib.next().await {
            let sound = Sound::from_str(&mci.data.custom_id).unwrap();
            // Acknowledge the interaction and send a reply
            mci.create_interaction_response(&ctx, |r| {
                // This time we dont edit the message but reply to it
                r.kind(InteractionResponseType::ChannelMessageWithSource).interaction_response_data(
                    |d| {
                        // Make the message hidden for other users by setting `ephemeral(true)`.
                        d.ephemeral(true).content(format!("The **{}** says __{}__", animal, sound))
                    },
                )
            })
            .await
            .unwrap();
        }

        // Delete the orig message or there will be dangling components
        m.delete(&ctx).await.unwrap()
    }
}

#[tokio::main]
async fn main() {
    dotenv().ok();
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN").expect("Expected a token in the environment");

    // Build our client.
    let intents = GatewayIntents::GUILD_MESSAGES
        | GatewayIntents::DIRECT_MESSAGES
        | GatewayIntents::MESSAGE_CONTENT;
    let mut client = Client::builder(token, intents)
        .event_handler(Handler)
        .await
        .expect("Error creating client");

    // Finally, start a single shard, and start listening to events.
    // Shards will automatically attempt to reconnect, and will perform
    // exponential backoff until it reconnects.
    if let Err(why) = client.start().await {
        println!("Client error: {:?}", why);
    }
}
<commit_msg>Simplify example 17, add more comments, add emoji example (#2135)<commit_after>use std::env;
use std::time::Duration;

use dotenv::dotenv;
use serenity::async_trait;
use serenity::builder::CreateButton;
use serenity::client::{Context, EventHandler};
use serenity::futures::StreamExt;
use serenity::model::application::component::ButtonStyle;
use serenity::model::prelude::*;
use serenity::prelude::*;

fn sound_button(name: &str, emoji: ReactionType) -> CreateButton {
    let mut b = CreateButton::default();
    b.custom_id(name);
    // To add an emoji to buttons, use .emoji(). The method accepts anything ReactionType or
    // anything that can be converted to it. For a list of that, search Trait Implementations in the
    // docs for From<...>.
    b.emoji(emoji);
    b.label(name);
    b.style(ButtonStyle::Primary);
    b
}

struct Handler;

#[async_trait]
impl EventHandler for Handler {
    async fn message(&self, ctx: Context, msg: Message) {
        if msg.content != "animal" {
            return;
        }

        // Ask the user for its favorite animal
        let m = msg
            .channel_id
            .send_message(&ctx, |m| {
                m.content("Please select your favorite animal").components(|c| {
                    c.create_action_row(|row| {
                        // An action row can only contain one select menu!
                        row.create_select_menu(|menu| {
                            menu.custom_id("animal_select");
                            menu.placeholder("No animal selected");
                            menu.options(|f| {
                                f.create_option(|o| o.label("🐈 meow").value("Cat"));
                                f.create_option(|o| o.label("🐕 woof").value("Dog"));
                                f.create_option(|o| o.label("🐎 neigh").value("Horse"));
                                f.create_option(|o| o.label("🦙 hoooooooonk").value("Alpaca"));
                                f.create_option(|o| o.label("🦀 crab rave").value("Ferris"))
                            })
                        })
                    })
                })
            })
            .await
            .unwrap();

        // Wait for the user to make a selection
        // This uses a collector to wait for an incoming event without needing to listen for it
        // manually in the EventHandler.
        let interaction =
            match m.await_component_interaction(&ctx).timeout(Duration::from_secs(60 * 3)).await {
                Some(x) => x,
                None => {
                    m.reply(&ctx, "Timed out").await.unwrap();
                    return;
                },
            };

        // data.values contains the selected value from each select menus. We only have one menu,
        // so we retrieve the first
        let animal = &interaction.data.values[0];

        // Acknowledge the interaction and edit the message
        interaction
            .create_interaction_response(&ctx, |r| {
                r.kind(InteractionResponseType::UpdateMessage).interaction_response_data(|d| {
                    d.content(format!("You chose: **{}**\nNow choose a sound!", animal)).components(
                        |c| {
                            c.create_action_row(|r| {
                                // add_XXX methods are an alternative to create_XXX methods
                                r.add_button(sound_button("meow", "🐈".parse().unwrap()));
                                r.add_button(sound_button("woof", "🐕".parse().unwrap()));
                                r.add_button(sound_button("neigh", "🐎".parse().unwrap()));
                                r.add_button(sound_button("hoooooooonk", "🦙".parse().unwrap()));
                                r.add_button(sound_button(
                                    "crab rave",
                                    // Custom emojis in Discord are represented with
                                    // `<:EMOJI_NAME:EMOJI_ID>`. You can see this by
                                    // posting an emoji in your server and putting a backslash
                                    // before the emoji.
                                    //
                                    // Because ReactionType implements FromStr, we can use .parse()
                                    // to convert the textual emoji representation to ReactionType
                                    "<:ferris:381919740114763787>".parse().unwrap(),
                                ))
                            })
                        },
                    )
                })
            })
            .await
            .unwrap();

        // Wait for multiple interactions
        let mut interaction_stream =
            m.await_component_interactions(&ctx).timeout(Duration::from_secs(60 * 3)).build();

        while let Some(interaction) = interaction_stream.next().await {
            let sound = &interaction.data.custom_id;
            // Acknowledge the interaction and send a reply
            interaction
                .create_interaction_response(&ctx, |r| {
                    // This time we dont edit the message but reply to it
                    r.kind(InteractionResponseType::ChannelMessageWithSource)
                        .interaction_response_data(|d| {
                            // Make the message hidden for other users by setting `ephemeral(true)`.
                            d.ephemeral(true)
                                .content(format!("The **{}** says __{}__", animal, sound))
                        })
                })
                .await
                .unwrap();
        }

        // Delete the orig message or there will be dangling components (components that still
        // exist, but no collector is running so any user who presses them sees an error)
        m.delete(&ctx).await.unwrap()
    }
}

#[tokio::main]
async fn main() {
    dotenv().ok();
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN").expect("Expected a token in the environment");

    // Build our client.
    let intents = GatewayIntents::GUILD_MESSAGES
        | GatewayIntents::DIRECT_MESSAGES
        | GatewayIntents::MESSAGE_CONTENT;
    let mut client = Client::builder(token, intents)
        .event_handler(Handler)
        .await
        .expect("Error creating client");

    // Finally, start a single shard, and start listening to events.
    // Shards will automatically attempt to reconnect, and will perform
    // exponential backoff until it reconnects.
    if let Err(why) = client.start().await {
        println!("Client error: {:?}", why);
    }
}
<|endoftext|>


<commit_before><commit_msg>Keep rustfmt from collapsing vertical layout<commit_after><|endoftext|>


<commit_before>//! This module provides a simplified abstraction for working with
//! code blocks identified by their integer `NodeId`. In particular,
//! it captures a common set of attributes that all "function-like
//! things" (represented by `FnLike` instances) share. For example,
//! all `FnLike` instances have a type signature (be it explicit or
//! inferred). And all `FnLike` instances have a body, i.e., the code
//! that is run when the function-like thing it represents is invoked.
//!
//! With the above abstraction in place, one can treat the program
//! text as a collection of blocks of code (and most such blocks are
//! nested within a uniquely determined `FnLike`), and users can ask
//! for the `Code` associated with a particular NodeId.

use crate::hir as ast;
use crate::hir::map;
use crate::hir::{Expr, FnDecl, Node};
use crate::hir::intravisit::FnKind;
use syntax::ast::{Attribute, Ident, NodeId};
use syntax_pos::Span;

/// An FnLikeNode is a Node that is like a fn, in that it has a decl
/// and a body (as well as a NodeId, a span, etc).
///
/// More specifically, it is one of either:
///
///   - A function item,
///   - A closure expr (i.e., an ExprKind::Closure), or
///   - The default implementation for a trait method.
///
/// To construct one, use the `Code::from_node` function.
#[derive(Copy, Clone, Debug)]
pub struct FnLikeNode<'a> { node: Node<'a> }

/// MaybeFnLike wraps a method that indicates if an object
/// corresponds to some FnLikeNode.
trait MaybeFnLike { fn is_fn_like(&self) -> bool; }

impl MaybeFnLike for ast::Item {
    fn is_fn_like(&self) -> bool {
        match self.node { ast::ItemKind::Fn(..) => true, _ => false, }
    }
}

impl MaybeFnLike for ast::ImplItem {
    fn is_fn_like(&self) -> bool {
        match self.node { ast::ImplItemKind::Method(..) => true, _ => false, }
    }
}

impl MaybeFnLike for ast::TraitItem {
    fn is_fn_like(&self) -> bool {
        match self.node {
            ast::TraitItemKind::Method(_, ast::TraitMethod::Provided(_)) => true,
            _ => false,
        }
    }
}

impl MaybeFnLike for ast::Expr {
    fn is_fn_like(&self) -> bool {
        match self.node {
            ast::ExprKind::Closure(..) => true,
            _ => false,
        }
    }
}

/// Carries either an FnLikeNode or a Expr, as these are the two
/// constructs that correspond to "code" (as in, something from which
/// we can construct a control-flow graph).
#[derive(Copy, Clone)]
pub enum Code<'a> {
    FnLike(FnLikeNode<'a>),
    Expr(&'a Expr),
}

impl<'a> Code<'a> {
    pub fn id(&self) -> ast::HirId {
        match *self {
            Code::FnLike(node) => node.id(),
            Code::Expr(block) => block.hir_id,
        }
    }

    /// Attempts to construct a Code from presumed FnLike or Expr node input.
    pub fn from_node(map: &map::Map<'a>, id: NodeId) -> Option<Code<'a>> {
        match map.get(id) {
            map::Node::Block(_) => {
                //  Use the parent, hopefully an expression node.
                Code::from_node(map, map.get_parent_node(id))
            }
            map::Node::Expr(expr) => Some(Code::Expr(expr)),
            node => FnLikeNode::from_node(node).map(Code::FnLike)
        }
    }
}

/// These are all the components one can extract from a fn item for
/// use when implementing FnLikeNode operations.
struct ItemFnParts<'a> {
    ident:    Ident,
    decl:     &'a ast::FnDecl,
    header:   ast::FnHeader,
    vis:      &'a ast::Visibility,
    generics: &'a ast::Generics,
    body:     ast::BodyId,
    id:       ast::HirId,
    span:     Span,
    attrs:    &'a [Attribute],
}

/// These are all the components one can extract from a closure expr
/// for use when implementing FnLikeNode operations.
struct ClosureParts<'a> {
    decl: &'a FnDecl,
    body: ast::BodyId,
    id: ast::HirId,
    span: Span,
    attrs: &'a [Attribute],
}

impl<'a> ClosureParts<'a> {
    fn new(d: &'a FnDecl, b: ast::BodyId, id: ast::HirId, s: Span, attrs: &'a [Attribute]) -> Self {
        ClosureParts {
            decl: d,
            body: b,
            id,
            span: s,
            attrs,
        }
    }
}

impl<'a> FnLikeNode<'a> {
    /// Attempts to construct a FnLikeNode from presumed FnLike node input.
    pub fn from_node(node: Node<'_>) -> Option<FnLikeNode<'_>> {
        let fn_like = match node {
            map::Node::Item(item) => item.is_fn_like(),
            map::Node::TraitItem(tm) => tm.is_fn_like(),
            map::Node::ImplItem(it) => it.is_fn_like(),
            map::Node::Expr(e) => e.is_fn_like(),
            _ => false
        };
        if fn_like {
            Some(FnLikeNode {
                node,
            })
        } else {
            None
        }
    }

    pub fn body(self) -> ast::BodyId {
        self.handle(|i: ItemFnParts<'a>| i.body,
                    |_, _, _: &'a ast::MethodSig, _, body: ast::BodyId, _, _| body,
                    |c: ClosureParts<'a>| c.body)
    }

    pub fn decl(self) -> &'a FnDecl {
        self.handle(|i: ItemFnParts<'a>| &*i.decl,
                    |_, _, sig: &'a ast::MethodSig, _, _, _, _| &sig.decl,
                    |c: ClosureParts<'a>| c.decl)
    }

    pub fn span(self) -> Span {
        self.handle(|i: ItemFnParts<'_>| i.span,
                    |_, _, _: &'a ast::MethodSig, _, _, span, _| span,
                    |c: ClosureParts<'_>| c.span)
    }

    pub fn id(self) -> ast::HirId {
        self.handle(|i: ItemFnParts<'_>| i.id,
                    |id, _, _: &'a ast::MethodSig, _, _, _, _| id,
                    |c: ClosureParts<'_>| c.id)
    }

    pub fn constness(self) -> ast::Constness {
        match self.kind() {
            FnKind::ItemFn(_, _, header, ..) => header.constness,
            FnKind::Method(_, m, ..) => m.header.constness,
            _ => ast::Constness::NotConst
        }
    }

    pub fn asyncness(self) -> ast::IsAsync {
        match self.kind() {
            FnKind::ItemFn(_, _, header, ..) => header.asyncness,
            FnKind::Method(_, m, ..) => m.header.asyncness,
            _ => ast::IsAsync::NotAsync
        }
    }

    pub fn unsafety(self) -> ast::Unsafety {
        match self.kind() {
            FnKind::ItemFn(_, _, header, ..) => header.unsafety,
            FnKind::Method(_, m, ..) => m.header.unsafety,
            _ => ast::Unsafety::Normal
        }
    }

    pub fn kind(self) -> FnKind<'a> {
        let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
            FnKind::ItemFn(p.ident, p.generics, p.header, p.vis, p.attrs)
        };
        let closure = |c: ClosureParts<'a>| {
            FnKind::Closure(c.attrs)
        };
        let method = |_, ident: Ident, sig: &'a ast::MethodSig, vis, _, _, attrs| {
            FnKind::Method(ident, sig, vis, attrs)
        };
        self.handle(item, method, closure)
    }

    fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A where
        I: FnOnce(ItemFnParts<'a>) -> A,
        M: FnOnce(ast::HirId,
                  Ident,
                  &'a ast::MethodSig,
                  Option<&'a ast::Visibility>,
                  ast::BodyId,
                  Span,
                  &'a [Attribute])
                  -> A,
        C: FnOnce(ClosureParts<'a>) -> A,
    {
        match self.node {
            map::Node::Item(i) => match i.node {
                ast::ItemKind::Fn(ref decl, header, ref generics, block) =>
                    item_fn(ItemFnParts {
                        id: i.hir_id,
                        ident: i.ident,
                        decl: &decl,
                        body: block,
                        vis: &i.vis,
                        span: i.span,
                        attrs: &i.attrs,
                        header,
                        generics,
                    }),
                _ => bug!("item FnLikeNode that is not fn-like"),
            },
            map::Node::TraitItem(ti) => match ti.node {
                ast::TraitItemKind::Method(ref sig, ast::TraitMethod::Provided(body)) => {
                    method(ti.hir_id, ti.ident, sig, None, body, ti.span, &ti.attrs)
                }
                _ => bug!("trait method FnLikeNode that is not fn-like"),
            },
            map::Node::ImplItem(ii) => {
                match ii.node {
                    ast::ImplItemKind::Method(ref sig, body) => {
                        method(ii.hir_id, ii.ident, sig, Some(&ii.vis), body, ii.span, &ii.attrs)
                    }
                    _ => bug!("impl method FnLikeNode that is not fn-like")
                }
            },
            map::Node::Expr(e) => match e.node {
                ast::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) =>
                    closure(ClosureParts::new(&decl, block, e.hir_id, e.span, &e.attrs)),
                _ => bug!("expr FnLikeNode that is not fn-like"),
            },
            _ => bug!("other FnLikeNode that is not fn-like"),
        }
    }
}
<commit_msg>Refactor some existing methods<commit_after>//! This module provides a simplified abstraction for working with
//! code blocks identified by their integer `NodeId`. In particular,
//! it captures a common set of attributes that all "function-like
//! things" (represented by `FnLike` instances) share. For example,
//! all `FnLike` instances have a type signature (be it explicit or
//! inferred). And all `FnLike` instances have a body, i.e., the code
//! that is run when the function-like thing it represents is invoked.
//!
//! With the above abstraction in place, one can treat the program
//! text as a collection of blocks of code (and most such blocks are
//! nested within a uniquely determined `FnLike`), and users can ask
//! for the `Code` associated with a particular NodeId.

use crate::hir as ast;
use crate::hir::map;
use crate::hir::{Expr, FnDecl, Node};
use crate::hir::intravisit::FnKind;
use syntax::ast::{Attribute, Ident, NodeId};
use syntax_pos::Span;

/// An FnLikeNode is a Node that is like a fn, in that it has a decl
/// and a body (as well as a NodeId, a span, etc).
///
/// More specifically, it is one of either:
///
///   - A function item,
///   - A closure expr (i.e., an ExprKind::Closure), or
///   - The default implementation for a trait method.
///
/// To construct one, use the `Code::from_node` function.
#[derive(Copy, Clone, Debug)]
pub struct FnLikeNode<'a> { node: Node<'a> }

/// MaybeFnLike wraps a method that indicates if an object
/// corresponds to some FnLikeNode.
trait MaybeFnLike { fn is_fn_like(&self) -> bool; }

impl MaybeFnLike for ast::Item {
    fn is_fn_like(&self) -> bool {
        match self.node { ast::ItemKind::Fn(..) => true, _ => false, }
    }
}

impl MaybeFnLike for ast::ImplItem {
    fn is_fn_like(&self) -> bool {
        match self.node { ast::ImplItemKind::Method(..) => true, _ => false, }
    }
}

impl MaybeFnLike for ast::TraitItem {
    fn is_fn_like(&self) -> bool {
        match self.node {
            ast::TraitItemKind::Method(_, ast::TraitMethod::Provided(_)) => true,
            _ => false,
        }
    }
}

impl MaybeFnLike for ast::Expr {
    fn is_fn_like(&self) -> bool {
        match self.node {
            ast::ExprKind::Closure(..) => true,
            _ => false,
        }
    }
}

/// Carries either an FnLikeNode or a Expr, as these are the two
/// constructs that correspond to "code" (as in, something from which
/// we can construct a control-flow graph).
#[derive(Copy, Clone)]
pub enum Code<'a> {
    FnLike(FnLikeNode<'a>),
    Expr(&'a Expr),
}

impl<'a> Code<'a> {
    pub fn id(&self) -> ast::HirId {
        match *self {
            Code::FnLike(node) => node.id(),
            Code::Expr(block) => block.hir_id,
        }
    }

    /// Attempts to construct a Code from presumed FnLike or Expr node input.
    pub fn from_node(map: &map::Map<'a>, id: NodeId) -> Option<Code<'a>> {
        match map.get(id) {
            map::Node::Block(_) => {
                //  Use the parent, hopefully an expression node.
                Code::from_node(map, map.get_parent_node(id))
            }
            map::Node::Expr(expr) => Some(Code::Expr(expr)),
            node => FnLikeNode::from_node(node).map(Code::FnLike)
        }
    }
}

/// These are all the components one can extract from a fn item for
/// use when implementing FnLikeNode operations.
struct ItemFnParts<'a> {
    ident:    Ident,
    decl:     &'a ast::FnDecl,
    header:   ast::FnHeader,
    vis:      &'a ast::Visibility,
    generics: &'a ast::Generics,
    body:     ast::BodyId,
    id:       ast::HirId,
    span:     Span,
    attrs:    &'a [Attribute],
}

/// These are all the components one can extract from a closure expr
/// for use when implementing FnLikeNode operations.
struct ClosureParts<'a> {
    decl: &'a FnDecl,
    body: ast::BodyId,
    id: ast::HirId,
    span: Span,
    attrs: &'a [Attribute],
}

impl<'a> ClosureParts<'a> {
    fn new(d: &'a FnDecl, b: ast::BodyId, id: ast::HirId, s: Span, attrs: &'a [Attribute]) -> Self {
        ClosureParts {
            decl: d,
            body: b,
            id,
            span: s,
            attrs,
        }
    }
}

impl<'a> FnLikeNode<'a> {
    /// Attempts to construct a FnLikeNode from presumed FnLike node input.
    pub fn from_node(node: Node<'_>) -> Option<FnLikeNode<'_>> {
        let fn_like = match node {
            map::Node::Item(item) => item.is_fn_like(),
            map::Node::TraitItem(tm) => tm.is_fn_like(),
            map::Node::ImplItem(it) => it.is_fn_like(),
            map::Node::Expr(e) => e.is_fn_like(),
            _ => false
        };
        if fn_like {
            Some(FnLikeNode {
                node,
            })
        } else {
            None
        }
    }

    pub fn body(self) -> ast::BodyId {
        self.handle(|i: ItemFnParts<'a>| i.body,
                    |_, _, _: &'a ast::MethodSig, _, body: ast::BodyId, _, _| body,
                    |c: ClosureParts<'a>| c.body)
    }

    pub fn decl(self) -> &'a FnDecl {
        self.handle(|i: ItemFnParts<'a>| &*i.decl,
                    |_, _, sig: &'a ast::MethodSig, _, _, _, _| &sig.decl,
                    |c: ClosureParts<'a>| c.decl)
    }

    pub fn span(self) -> Span {
        self.handle(|i: ItemFnParts<'_>| i.span,
                    |_, _, _: &'a ast::MethodSig, _, _, span, _| span,
                    |c: ClosureParts<'_>| c.span)
    }

    pub fn id(self) -> ast::HirId {
        self.handle(|i: ItemFnParts<'_>| i.id,
                    |id, _, _: &'a ast::MethodSig, _, _, _, _| id,
                    |c: ClosureParts<'_>| c.id)
    }

    pub fn constness(self) -> ast::Constness {
        self.kind().header().map_or(ast::Constness::NotConst, |header| header.constness)
    }

    pub fn asyncness(self) -> ast::IsAsync {
        self.kind().header().map_or(ast::IsAsync::NotAsync, |header| header.asyncness)
    }

    pub fn unsafety(self) -> ast::Unsafety {
        self.kind().header().map_or(ast::Unsafety::Normal, |header| header.unsafety)
    }

    pub fn kind(self) -> FnKind<'a> {
        let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
            FnKind::ItemFn(p.ident, p.generics, p.header, p.vis, p.attrs)
        };
        let closure = |c: ClosureParts<'a>| {
            FnKind::Closure(c.attrs)
        };
        let method = |_, ident: Ident, sig: &'a ast::MethodSig, vis, _, _, attrs| {
            FnKind::Method(ident, sig, vis, attrs)
        };
        self.handle(item, method, closure)
    }

    fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A where
        I: FnOnce(ItemFnParts<'a>) -> A,
        M: FnOnce(ast::HirId,
                  Ident,
                  &'a ast::MethodSig,
                  Option<&'a ast::Visibility>,
                  ast::BodyId,
                  Span,
                  &'a [Attribute])
                  -> A,
        C: FnOnce(ClosureParts<'a>) -> A,
    {
        match self.node {
            map::Node::Item(i) => match i.node {
                ast::ItemKind::Fn(ref decl, header, ref generics, block) =>
                    item_fn(ItemFnParts {
                        id: i.hir_id,
                        ident: i.ident,
                        decl: &decl,
                        body: block,
                        vis: &i.vis,
                        span: i.span,
                        attrs: &i.attrs,
                        header,
                        generics,
                    }),
                _ => bug!("item FnLikeNode that is not fn-like"),
            },
            map::Node::TraitItem(ti) => match ti.node {
                ast::TraitItemKind::Method(ref sig, ast::TraitMethod::Provided(body)) => {
                    method(ti.hir_id, ti.ident, sig, None, body, ti.span, &ti.attrs)
                }
                _ => bug!("trait method FnLikeNode that is not fn-like"),
            },
            map::Node::ImplItem(ii) => {
                match ii.node {
                    ast::ImplItemKind::Method(ref sig, body) => {
                        method(ii.hir_id, ii.ident, sig, Some(&ii.vis), body, ii.span, &ii.attrs)
                    }
                    _ => bug!("impl method FnLikeNode that is not fn-like")
                }
            },
            map::Node::Expr(e) => match e.node {
                ast::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) =>
                    closure(ClosureParts::new(&decl, block, e.hir_id, e.span, &e.attrs)),
                _ => bug!("expr FnLikeNode that is not fn-like"),
            },
            _ => bug!("other FnLikeNode that is not fn-like"),
        }
    }
}
<|endoftext|>


<commit_before>//! Intermediate representation of a function.
//!
//! The `Function` struct defined in this module owns all of its extended basic blocks and
//! instructions.

use ir::{FunctionName, Signature, StackSlot, StackSlotData, JumpTable, JumpTableData,
         DataFlowGraph, Layout};
use entity_map::{EntityMap, PrimaryEntityData};
use std::fmt::{self, Display, Debug, Formatter};
use write::write_function;

/// A function.
///
/// Functions can be cloned, but it is not a very fast operation.
/// The clone will have all the same entity numbers as the original.
#[derive(Clone)]
pub struct Function {
    /// Name of this function. Mostly used by `.cton` files.
    pub name: FunctionName,

    /// Signature of this function.
    signature: Signature,

    /// Stack slots allocated in this function.
    pub stack_slots: EntityMap<StackSlot, StackSlotData>,

    /// Jump tables used in this function.
    pub jump_tables: EntityMap<JumpTable, JumpTableData>,

    /// Data flow graph containing the primary definition of all instructions, EBBs and values.
    pub dfg: DataFlowGraph,

    /// Layout of EBBs and instructions in the function body.
    pub layout: Layout,
}

impl PrimaryEntityData for StackSlotData {}
impl PrimaryEntityData for JumpTableData {}

impl Function {
    /// Create a function with the given name and signature.
    pub fn with_name_signature(name: FunctionName, sig: Signature) -> Function {
        Function {
            name: name,
            signature: sig,
            stack_slots: EntityMap::new(),
            jump_tables: EntityMap::new(),
            dfg: DataFlowGraph::new(),
            layout: Layout::new(),
        }
    }

    /// Create a new empty, anomymous function.
    pub fn new() -> Function {
        Self::with_name_signature(FunctionName::default(), Signature::new())
    }

    /// Get the signature of this function.
    pub fn own_signature(&self) -> &Signature {
        &self.signature
    }
}

impl Display for Function {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write_function(fmt, self)
    }
}

impl Debug for Function {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write_function(fmt, self)
    }
}
<commit_msg>Store instruction encodings in Function.<commit_after>//! Intermediate representation of a function.
//!
//! The `Function` struct defined in this module owns all of its extended basic blocks and
//! instructions.

use std::fmt::{self, Display, Debug, Formatter};
use ir::{FunctionName, Signature, Inst, StackSlot, StackSlotData, JumpTable, JumpTableData,
         DataFlowGraph, Layout};
use isa::Encoding;
use entity_map::{EntityMap, PrimaryEntityData};
use write::write_function;

/// A function.
///
/// Functions can be cloned, but it is not a very fast operation.
/// The clone will have all the same entity numbers as the original.
#[derive(Clone)]
pub struct Function {
    /// Name of this function. Mostly used by `.cton` files.
    pub name: FunctionName,

    /// Signature of this function.
    signature: Signature,

    /// Stack slots allocated in this function.
    pub stack_slots: EntityMap<StackSlot, StackSlotData>,

    /// Jump tables used in this function.
    pub jump_tables: EntityMap<JumpTable, JumpTableData>,

    /// Data flow graph containing the primary definition of all instructions, EBBs and values.
    pub dfg: DataFlowGraph,

    /// Layout of EBBs and instructions in the function body.
    pub layout: Layout,

    /// Encoding recipe and bits for the legal instructions.
    /// Illegal instructions have the `Encoding::default()` value.
    pub encodings: EntityMap<Inst, Encoding>,
}

impl PrimaryEntityData for StackSlotData {}
impl PrimaryEntityData for JumpTableData {}

impl Function {
    /// Create a function with the given name and signature.
    pub fn with_name_signature(name: FunctionName, sig: Signature) -> Function {
        Function {
            name: name,
            signature: sig,
            stack_slots: EntityMap::new(),
            jump_tables: EntityMap::new(),
            dfg: DataFlowGraph::new(),
            layout: Layout::new(),
            encodings: EntityMap::new(),
        }
    }

    /// Create a new empty, anomymous function.
    pub fn new() -> Function {
        Self::with_name_signature(FunctionName::default(), Signature::new())
    }

    /// Get the signature of this function.
    pub fn own_signature(&self) -> &Signature {
        &self.signature
    }
}

impl Display for Function {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write_function(fmt, self)
    }
}

impl Debug for Function {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write_function(fmt, self)
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

#![allow(dead_code)] // runtime init functions not used during testing

use os::windows::prelude::*;
use sys::windows::os::current_exe;
use sys::c;
use ffi::OsString;
use fmt;
use vec;
use core::iter;
use slice;
use path::PathBuf;

pub unsafe fn init(_argc: isize, _argv: *const *const u8) { }

pub unsafe fn cleanup() { }

pub fn args() -> Args {
    unsafe {
        let lp_cmd_line = c::GetCommandLineW();
        let parsed_args_list = parse_lp_cmd_line(
            lp_cmd_line as *const u16,
            || current_exe().map(PathBuf::into_os_string).unwrap_or_else(|_| OsString::new()));

        Args { parsed_args_list: parsed_args_list }
    }
}

/// Implements the Windows command-line argument parsing algorithm.
///
/// Microsoft's documentation for the Windows CLI argument format can be found at
/// <https://docs.microsoft.com/en-us/previous-versions//17w5ykft(v=vs.85)>.
///
/// Windows includes a function to do this in shell32.dll,
/// but linking with that DLL causes the process to be registered as a GUI application.
/// GUI applications add a bunch of overhead, even if no windows are drawn. See
/// <https://randomascii.wordpress.com/2018/12/03/a-not-called-function-can-cause-a-5x-slowdown/>.
///
/// This function was tested for equivalence to the shell32.dll implementation in
/// Windows 10 Pro v1803, using an exhaustive test suite available at
/// <https://gist.github.com/notriddle/dde431930c392e428055b2dc22e638f5> or
/// <https://paste.gg/p/anonymous/47d6ed5f5bd549168b1c69c799825223>.
unsafe fn parse_lp_cmd_line<F: Fn() -> OsString>(lp_cmd_line: *const u16, exe_name: F)
                                                 -> vec::IntoIter<OsString> {
    const BACKSLASH: u16 = '\\' as u16;
    const QUOTE: u16 = '"' as u16;
    const TAB: u16 = '\t' as u16;
    const SPACE: u16 = ' ' as u16;
    let mut in_quotes = false;
    let mut was_in_quotes = false;
    let mut backslash_count: usize = 0;
    let mut ret_val = Vec::new();
    let mut cur = Vec::new();
    if lp_cmd_line.is_null() || *lp_cmd_line == 0 {
        ret_val.push(exe_name());
        return ret_val.into_iter();
    }
    let mut i = 0;
    // The executable name at the beginning is special.
    match *lp_cmd_line {
        // The executable name ends at the next quote mark,
        // no matter what.
        QUOTE => {
            loop {
                i += 1;
                let c = *lp_cmd_line.offset(i);
                if c == 0 {
                    ret_val.push(OsString::from_wide(
                        slice::from_raw_parts(lp_cmd_line.offset(1), i as usize - 1)
                    ));
                    return ret_val.into_iter();
                }
                if c == QUOTE {
                    break;
                }
            }
            ret_val.push(OsString::from_wide(
                slice::from_raw_parts(lp_cmd_line.offset(1), i as usize - 1)
            ));
            i += 1;
        }
        // Implement quirk: when they say whitespace here,
        // they include the entire ASCII control plane:
        // "However, if lpCmdLine starts with any amount of whitespace, CommandLineToArgvW
        // will consider the first argument to be an empty string. Excess whitespace at the
        // end of lpCmdLine is ignored."
        0...SPACE => {
            ret_val.push(OsString::new());
            i += 1;
        },
        // The executable name ends at the next whitespace,
        // no matter what.
        _ => {
            loop {
                i += 1;
                let c = *lp_cmd_line.offset(i);
                if c == 0 {
                    ret_val.push(OsString::from_wide(
                        slice::from_raw_parts(lp_cmd_line, i as usize)
                    ));
                    return ret_val.into_iter();
                }
                if c > 0 && c <= SPACE {
                    break;
                }
            }
            ret_val.push(OsString::from_wide(
                slice::from_raw_parts(lp_cmd_line, i as usize)
            ));
            i += 1;
        }
    }
    loop {
        let c = *lp_cmd_line.offset(i);
        match c {
            // backslash
            BACKSLASH => {
                backslash_count += 1;
                was_in_quotes = false;
            },
            QUOTE if backslash_count % 2 == 0 => {
                cur.extend(iter::repeat(b'\\' as u16).take(backslash_count / 2));
                backslash_count = 0;
                if was_in_quotes {
                    cur.push('"' as u16);
                    was_in_quotes = false;
                } else {
                    was_in_quotes = in_quotes;
                    in_quotes = !in_quotes;
                }
            }
            QUOTE if backslash_count % 2 != 0 => {
                cur.extend(iter::repeat(b'\\' as u16).take(backslash_count / 2));
                backslash_count = 0;
                was_in_quotes = false;
                cur.push(b'"' as u16);
            }
            SPACE | TAB if !in_quotes => {
                cur.extend(iter::repeat(b'\\' as u16).take(backslash_count));
                if !cur.is_empty() || was_in_quotes {
                    ret_val.push(OsString::from_wide(&cur[..]));
                    cur.truncate(0);
                }
                backslash_count = 0;
                was_in_quotes = false;
            }
            0x00 => {
                cur.extend(iter::repeat(b'\\' as u16).take(backslash_count));
                // include empty quoted strings at the end of the arguments list
                if !cur.is_empty() || was_in_quotes || in_quotes {
                    ret_val.push(OsString::from_wide(&cur[..]));
                }
                break;
            }
            _ => {
                cur.extend(iter::repeat(b'\\' as u16).take(backslash_count));
                backslash_count = 0;
                was_in_quotes = false;
                cur.push(c);
            }
        }
        i += 1;
    }
    ret_val.into_iter()
}

pub struct Args {
    parsed_args_list: vec::IntoIter<OsString>,
}

pub struct ArgsInnerDebug<'a> {
    args: &'a Args,
}

impl<'a> fmt::Debug for ArgsInnerDebug<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("[")?;
        let mut first = true;
        for i in self.args.parsed_args_list.as_slice() {
            if !first {
                f.write_str(", ")?;
            }
            first = false;

            fmt::Debug::fmt(i, f)?;
        }
        f.write_str("]")?;
        Ok(())
    }
}

impl Args {
    pub fn inner_debug(&self) -> ArgsInnerDebug {
        ArgsInnerDebug {
            args: self
        }
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> { self.parsed_args_list.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.parsed_args_list.size_hint() }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> { self.parsed_args_list.next_back() }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize { self.parsed_args_list.len() }
}

#[cfg(test)]
mod tests {
    use sys::windows::args::*;
    use ffi::OsString;

    fn chk(string: &str, parts: &[&str]) {
        let mut wide: Vec<u16> = OsString::from(string).encode_wide().collect();
        wide.push(0);
        let parsed = unsafe {
            parse_lp_cmd_line(wide.as_ptr() as *const u16, || OsString::from("TEST.EXE"))
        };
        let expected: Vec<OsString> = parts.iter().map(|k| OsString::from(k)).collect();
        assert_eq!(parsed.as_slice(), expected.as_slice());
    }

    #[test]
    fn empty() {
        chk("", &["TEST.EXE"]);
        chk("\0", &["TEST.EXE"]);
    }

    #[test]
    fn single_words() {
        chk("EXE one_word", &["EXE", "one_word"]);
        chk("EXE a", &["EXE", "a"]);
        chk("EXE 😅", &["EXE", "😅"]);
        chk("EXE 😅🤦", &["EXE", "😅🤦"]);
    }

    #[test]
    fn official_examples() {
        chk(r#"EXE "abc" d e"#, &["EXE", "abc", "d", "e"]);
        chk(r#"EXE a\\\b d"e f"g h"#, &["EXE", r#"a\\\b"#, "de fg", "h"]);
        chk(r#"EXE a\\\"b c d"#, &["EXE", r#"a\"b"#, "c", "d"]);
        chk(r#"EXE a\\\\"b c" d e"#, &["EXE", r#"a\\b c"#, "d", "e"]);
    }

    #[test]
    fn whitespace_behavior() {
        chk(r#" test"#, &["", "test"]);
        chk(r#"  test"#, &["", "test"]);
        chk(r#" test test2"#, &["", "test", "test2"]);
        chk(r#" test  test2"#, &["", "test", "test2"]);
        chk(r#"test test2 "#, &["test", "test2"]);
        chk(r#"test  test2 "#, &["test", "test2"]);
        chk(r#"test "#, &["test"]);
    }

    #[test]
    fn genius_quotes() {
        chk(r#"EXE "" """#, &["EXE", "", ""]);
        chk(r#"EXE "" """"#, &["EXE", "", "\""]);
        chk(
            r#"EXE "this is """all""" in the same argument""#,
            &["EXE", "this is \"all\" in the same argument"]
        );
        chk(r#"EXE "a"""#, &["EXE", "a\""]);
        chk(r#"EXE "a"" a"#, &["EXE", "a\"", "a"]);
    }
}
<commit_msg>Fix iterator nits<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

#![allow(dead_code)] // runtime init functions not used during testing

use os::windows::prelude::*;
use sys::windows::os::current_exe;
use sys::c;
use ffi::OsString;
use fmt;
use vec;
use core::iter;
use slice;
use path::PathBuf;

pub unsafe fn init(_argc: isize, _argv: *const *const u8) { }

pub unsafe fn cleanup() { }

pub fn args() -> Args {
    unsafe {
        let lp_cmd_line = c::GetCommandLineW();
        let parsed_args_list = parse_lp_cmd_line(
            lp_cmd_line as *const u16,
            || current_exe().map(PathBuf::into_os_string).unwrap_or_else(|_| OsString::new()));

        Args { parsed_args_list: parsed_args_list.into_iter() }
    }
}

/// Implements the Windows command-line argument parsing algorithm.
///
/// Microsoft's documentation for the Windows CLI argument format can be found at
/// <https://docs.microsoft.com/en-us/previous-versions//17w5ykft(v=vs.85)>.
///
/// Windows includes a function to do this in shell32.dll,
/// but linking with that DLL causes the process to be registered as a GUI application.
/// GUI applications add a bunch of overhead, even if no windows are drawn. See
/// <https://randomascii.wordpress.com/2018/12/03/a-not-called-function-can-cause-a-5x-slowdown/>.
///
/// This function was tested for equivalence to the shell32.dll implementation in
/// Windows 10 Pro v1803, using an exhaustive test suite available at
/// <https://gist.github.com/notriddle/dde431930c392e428055b2dc22e638f5> or
/// <https://paste.gg/p/anonymous/47d6ed5f5bd549168b1c69c799825223>.
unsafe fn parse_lp_cmd_line<F: Fn() -> OsString>(lp_cmd_line: *const u16, exe_name: F)
                                                 -> Vec<OsString> {
    const BACKSLASH: u16 = '\\' as u16;
    const QUOTE: u16 = '"' as u16;
    const TAB: u16 = '\t' as u16;
    const SPACE: u16 = ' ' as u16;
    let mut in_quotes = false;
    let mut was_in_quotes = false;
    let mut backslash_count: usize = 0;
    let mut ret_val = Vec::new();
    let mut cur = Vec::new();
    if lp_cmd_line.is_null() || *lp_cmd_line == 0 {
        ret_val.push(exe_name());
        return ret_val;
    }
    let mut i = 0;
    // The executable name at the beginning is special.
    match *lp_cmd_line {
        // The executable name ends at the next quote mark,
        // no matter what.
        QUOTE => {
            loop {
                i += 1;
                let c = *lp_cmd_line.offset(i);
                if c == 0 {
                    ret_val.push(OsString::from_wide(
                        slice::from_raw_parts(lp_cmd_line.offset(1), i as usize - 1)
                    ));
                    return ret_val;
                }
                if c == QUOTE {
                    break;
                }
            }
            ret_val.push(OsString::from_wide(
                slice::from_raw_parts(lp_cmd_line.offset(1), i as usize - 1)
            ));
            i += 1;
        }
        // Implement quirk: when they say whitespace here,
        // they include the entire ASCII control plane:
        // "However, if lpCmdLine starts with any amount of whitespace, CommandLineToArgvW
        // will consider the first argument to be an empty string. Excess whitespace at the
        // end of lpCmdLine is ignored."
        0...SPACE => {
            ret_val.push(OsString::new());
            i += 1;
        },
        // The executable name ends at the next whitespace,
        // no matter what.
        _ => {
            loop {
                i += 1;
                let c = *lp_cmd_line.offset(i);
                if c == 0 {
                    ret_val.push(OsString::from_wide(
                        slice::from_raw_parts(lp_cmd_line, i as usize)
                    ));
                    return ret_val;
                }
                if c > 0 && c <= SPACE {
                    break;
                }
            }
            ret_val.push(OsString::from_wide(
                slice::from_raw_parts(lp_cmd_line, i as usize)
            ));
            i += 1;
        }
    }
    loop {
        let c = *lp_cmd_line.offset(i);
        match c {
            // backslash
            BACKSLASH => {
                backslash_count += 1;
                was_in_quotes = false;
            },
            QUOTE if backslash_count % 2 == 0 => {
                cur.extend(iter::repeat(b'\\' as u16).take(backslash_count / 2));
                backslash_count = 0;
                if was_in_quotes {
                    cur.push('"' as u16);
                    was_in_quotes = false;
                } else {
                    was_in_quotes = in_quotes;
                    in_quotes = !in_quotes;
                }
            }
            QUOTE if backslash_count % 2 != 0 => {
                cur.extend(iter::repeat(b'\\' as u16).take(backslash_count / 2));
                backslash_count = 0;
                was_in_quotes = false;
                cur.push(b'"' as u16);
            }
            SPACE | TAB if !in_quotes => {
                cur.extend(iter::repeat(b'\\' as u16).take(backslash_count));
                if !cur.is_empty() || was_in_quotes {
                    ret_val.push(OsString::from_wide(&cur[..]));
                    cur.truncate(0);
                }
                backslash_count = 0;
                was_in_quotes = false;
            }
            0x00 => {
                cur.extend(iter::repeat(b'\\' as u16).take(backslash_count));
                // include empty quoted strings at the end of the arguments list
                if !cur.is_empty() || was_in_quotes || in_quotes {
                    ret_val.push(OsString::from_wide(&cur[..]));
                }
                break;
            }
            _ => {
                cur.extend(iter::repeat(b'\\' as u16).take(backslash_count));
                backslash_count = 0;
                was_in_quotes = false;
                cur.push(c);
            }
        }
        i += 1;
    }
    ret_val
}

pub struct Args {
    parsed_args_list: vec::IntoIter<OsString>,
}

pub struct ArgsInnerDebug<'a> {
    args: &'a Args,
}

impl<'a> fmt::Debug for ArgsInnerDebug<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.args.parsed_args_list.as_slice().fmt(f)
    }
}

impl Args {
    pub fn inner_debug(&self) -> ArgsInnerDebug {
        ArgsInnerDebug {
            args: self
        }
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> { self.parsed_args_list.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.parsed_args_list.size_hint() }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> { self.parsed_args_list.next_back() }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize { self.parsed_args_list.len() }
}

#[cfg(test)]
mod tests {
    use sys::windows::args::*;
    use ffi::OsString;

    fn chk(string: &str, parts: &[&str]) {
        let mut wide: Vec<u16> = OsString::from(string).encode_wide().collect();
        wide.push(0);
        let parsed = unsafe {
            parse_lp_cmd_line(wide.as_ptr() as *const u16, || OsString::from("TEST.EXE"))
        };
        let expected: Vec<OsString> = parts.iter().map(|k| OsString::from(k)).collect();
        assert_eq!(parsed.as_slice(), expected.as_slice());
    }

    #[test]
    fn empty() {
        chk("", &["TEST.EXE"]);
        chk("\0", &["TEST.EXE"]);
    }

    #[test]
    fn single_words() {
        chk("EXE one_word", &["EXE", "one_word"]);
        chk("EXE a", &["EXE", "a"]);
        chk("EXE 😅", &["EXE", "😅"]);
        chk("EXE 😅🤦", &["EXE", "😅🤦"]);
    }

    #[test]
    fn official_examples() {
        chk(r#"EXE "abc" d e"#, &["EXE", "abc", "d", "e"]);
        chk(r#"EXE a\\\b d"e f"g h"#, &["EXE", r#"a\\\b"#, "de fg", "h"]);
        chk(r#"EXE a\\\"b c d"#, &["EXE", r#"a\"b"#, "c", "d"]);
        chk(r#"EXE a\\\\"b c" d e"#, &["EXE", r#"a\\b c"#, "d", "e"]);
    }

    #[test]
    fn whitespace_behavior() {
        chk(r#" test"#, &["", "test"]);
        chk(r#"  test"#, &["", "test"]);
        chk(r#" test test2"#, &["", "test", "test2"]);
        chk(r#" test  test2"#, &["", "test", "test2"]);
        chk(r#"test test2 "#, &["test", "test2"]);
        chk(r#"test  test2 "#, &["test", "test2"]);
        chk(r#"test "#, &["test"]);
    }

    #[test]
    fn genius_quotes() {
        chk(r#"EXE "" """#, &["EXE", "", ""]);
        chk(r#"EXE "" """"#, &["EXE", "", "\""]);
        chk(
            r#"EXE "this is """all""" in the same argument""#,
            &["EXE", "this is \"all\" in the same argument"]
        );
        chk(r#"EXE "a"""#, &["EXE", "a\""]);
        chk(r#"EXE "a"" a"#, &["EXE", "a\"", "a"]);
    }
}
<|endoftext|>


<commit_before>#![warn(rust_2018_idioms, single_use_lifetimes)]

use std::{env, process::Command};

fn main() {
    if is_nightly() {
        println!("cargo:rustc-cfg=nightly");
    }
}

fn is_nightly() -> bool {
    env::var_os("RUSTC")
        .and_then(|rustc| Command::new(rustc).arg("--version").output().ok())
        .and_then(|output| String::from_utf8(output.stdout).ok())
        .map_or(false, |version| version.contains("nightly"))
}
<commit_msg>Update build scripts<commit_after>#![warn(rust_2018_idioms, single_use_lifetimes)]

use std::{env, process::Command};

fn main() {
    if is_nightly() {
        println!("cargo:rustc-cfg=nightly");
    }
}

fn is_nightly() -> bool {
    env::var_os("RUSTC")
        .and_then(|rustc| Command::new(rustc).arg("--version").output().ok())
        .and_then(|output| String::from_utf8(output.stdout).ok())
        .map_or(false, |version| version.contains("nightly") || version.contains("dev"))
}
<|endoftext|>