<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

/// Builds a `RenderPass` object whose template parameter is of indeterminate type.
#[macro_export]
macro_rules! single_pass_renderpass {
    (
        $device:expr,
        attachments: { $($a:tt)* },
        pass: {
            color: [$($color_atch:ident),*],
            depth_stencil: {$($depth_atch:ident)*}$(,)*
            $(resolve: [$($resolve_atch:ident),*])*$(,)*
        }
    ) => (
        $crate::ordered_passes_renderpass!(
            $device,
            attachments: { $($a)* },
            passes: [
                {
                    color: [$($color_atch),*],
                    depth_stencil: {$($depth_atch)*},
                    input: [],
                    resolve: [$($($resolve_atch),*)*]
                }
            ]
        )
    )
}

/// Builds a `RenderPass` object whose template parameter is of indeterminate type.
#[macro_export]
macro_rules! ordered_passes_renderpass {
    (
        $device:expr,
        attachments: {
            $(
                $atch_name:ident: {
                    load: $load:ident,
                    store: $store:ident,
                    format: $format:expr,
                    samples: $samples:expr,
                    $(initial_layout: $init_layout:expr,)*
                    $(final_layout: $final_layout:expr,)*
                }
            ),*
        },
        passes: [
            $(
                {
                    color: [$($color_atch:ident),*],
                    depth_stencil: {$($depth_atch:ident)*},
                    input: [$($input_atch:ident),*]$(,)*
                    $(resolve: [$($resolve_atch:ident),*])*$(,)*
                }
            ),*
        ]
    ) => ({
        use $crate::render_pass::RenderPass;

        let create_info = {
            #[allow(unused)]
            let mut attachment_num = 0;
            $(
                let $atch_name = attachment_num;
                attachment_num += 1;
            )*

            #[allow(unused)]
            let mut layouts: Vec<(
                Option<$crate::image::ImageLayout>,
                Option<$crate::image::ImageLayout>
            )> = vec![(None, None); attachment_num as usize];

            let subpasses = vec![
                $({
                    let desc = $crate::render_pass::SubpassDescription {
                        color_attachments: vec![
                            $({
                                let layout = &mut layouts[$color_atch as usize];
                                layout.0 = layout.0.or(Some($crate::image::ImageLayout::ColorAttachmentOptimal));
                                layout.1 = Some($crate::image::ImageLayout::ColorAttachmentOptimal);

                                Some($crate::render_pass::AttachmentReference {
                                    attachment: $color_atch,
                                    layout: $crate::image::ImageLayout::ColorAttachmentOptimal,
                                    ..Default::default()
                                })
                            }),*
                        ],
                        depth_stencil_attachment: {
                            let depth: Option<$crate::render_pass::AttachmentReference> = None;
                            $(
                                let layout = &mut layouts[$depth_atch as usize];
                                layout.1 = Some($crate::image::ImageLayout::DepthStencilAttachmentOptimal);
                                layout.0 = layout.0.or(layout.1);

                                let depth = Some($crate::render_pass::AttachmentReference {
                                    attachment: $depth_atch,
                                    layout: $crate::image::ImageLayout::DepthStencilAttachmentOptimal,
                                    ..Default::default()
                                });
                            )*
                            depth
                        },
                        input_attachments: vec![
                            $({
                                let layout = &mut layouts[$input_atch as usize];
                                layout.1 = Some($crate::image::ImageLayout::ShaderReadOnlyOptimal);
                                layout.0 = layout.0.or(layout.1);

                                Some($crate::render_pass::AttachmentReference {
                                    attachment: $input_atch,
                                    layout: $crate::image::ImageLayout::ShaderReadOnlyOptimal,
                                    ..Default::default()
                                })
                            }),*
                        ],
                        resolve_attachments: vec![
                            $($({
                                let layout = &mut layouts[$resolve_atch as usize];
                                layout.1 = Some($crate::image::ImageLayout::TransferDstOptimal);
                                layout.0 = layout.0.or(layout.1);

                                Some($crate::render_pass::AttachmentReference {
                                    attachment: $resolve_atch,
                                    layout: $crate::image::ImageLayout::TransferDstOptimal,
                                    ..Default::default()
                                })
                            }),*)*
                        ],
                        preserve_attachments: (0 .. attachment_num).filter(|&a| {
                            $(if a == $color_atch { return false; })*
                            $(if a == $depth_atch { return false; })*
                            $(if a == $input_atch { return false; })*
                            $($(if a == $resolve_atch { return false; })*)*
                            true
                        }).collect(),
                        ..Default::default()
                    };

                    assert!(desc.resolve_attachments.is_empty() ||
                            desc.resolve_attachments.len() == desc.color_attachments.len());
                    desc
                }),*
            ];

            let dependencies: Vec<_> = (0..subpasses.len().saturating_sub(1) as u32)
                .map(|id| {
                    // TODO: correct values
                    let src_stages = $crate::sync::PipelineStages {
                        all_graphics: true,
                        ..$crate::sync::PipelineStages::empty()
                    };
                    let dst_stages = $crate::sync::PipelineStages {
                        all_graphics: true,
                        ..$crate::sync::PipelineStages::empty()
                    };
                    let src_access = src_stages.supported_access();
                    let dst_access = dst_stages.supported_access();

                    $crate::render_pass::SubpassDependency {
                        src_subpass: id.into(),
                        dst_subpass: (id + 1).into(),
                        src_stages,
                        dst_stages,
                        src_access,
                        dst_access,
                        by_region: true,                      // TODO: correct values
                        ..Default::default()
                    }
                })
                .collect();

            let attachments = vec![
                $({
                    let layout = &mut layouts[$atch_name as usize];
                    $(layout.0 = Some($init_layout);)*
                    $(layout.1 = Some($final_layout);)*

                    $crate::render_pass::AttachmentDescription {
                        format: Some($format),
                        samples: $crate::image::SampleCount::try_from($samples).unwrap(),
                        load_op: $crate::render_pass::LoadOp::$load,
                        store_op: $crate::render_pass::StoreOp::$store,
                        stencil_load_op: $crate::render_pass::LoadOp::$load,
                        stencil_store_op: $crate::render_pass::StoreOp::$store,
                        initial_layout: layout.0.expect(
                            format!(
                                "Attachment {} is missing initial_layout, this is normally \
                                automatically determined but you can manually specify it for an individual \
                                attachment in the single_pass_renderpass! macro",
                                attachment_num
                            )
                            .as_ref(),
                        ),
                        final_layout: layout.1.expect(
                            format!(
                                "Attachment {} is missing final_layout, this is normally \
                                automatically determined but you can manually specify it for an individual \
                                attachment in the single_pass_renderpass! macro",
                                attachment_num
                            )
                            .as_ref(),
                        ),
                        ..Default::default()
                    }
                }),*
            ];

            $crate::render_pass::RenderPassCreateInfo {
                attachments,
                subpasses,
                dependencies,
                ..Default::default()
            }
        };

        RenderPass::new($device, create_info)
    });
}

#[cfg(test)]
mod tests {
    use crate::format::Format;

    #[test]
    fn single_pass_resolve() {
        let (device, _) = gfx_dev_and_queue!();
        let _ = single_pass_renderpass!(device,
            attachments: {
                a: {
                    load: Clear,
                    store: DontCare,
                    format: Format::R8G8B8A8_UNORM,
                    samples: 4,
                },
                b: {
                    load: DontCare,
                    store: Store,
                    format: Format::R8G8B8A8_UNORM,
                    samples: 1,
                }
            },
            pass: {
                color: [a],
                depth_stencil: {},
                resolve: [b],
            }
        )
        .unwrap();
    }
}
<commit_msg>Fix #2047 (#2048)<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

/// Builds a `RenderPass` object whose template parameter is of indeterminate type.
#[macro_export]
macro_rules! single_pass_renderpass {
    (
        $device:expr,
        attachments: { $($a:tt)* },
        pass: {
            color: [$($color_atch:ident),*],
            depth_stencil: {$($depth_atch:ident)*}$(,)*
            $(resolve: [$($resolve_atch:ident),*])*$(,)*
        }
    ) => (
        $crate::ordered_passes_renderpass!(
            $device,
            attachments: { $($a)* },
            passes: [
                {
                    color: [$($color_atch),*],
                    depth_stencil: {$($depth_atch)*},
                    input: [],
                    resolve: [$($($resolve_atch),*)*]
                }
            ]
        )
    )
}

/// Builds a `RenderPass` object whose template parameter is of indeterminate type.
#[macro_export]
macro_rules! ordered_passes_renderpass {
    (
        $device:expr,
        attachments: {
            $(
                $atch_name:ident: {
                    load: $load:ident,
                    store: $store:ident,
                    format: $format:expr,
                    samples: $samples:expr,
                    $(initial_layout: $init_layout:expr,)*
                    $(final_layout: $final_layout:expr,)*
                }
            ),*
        },
        passes: [
            $(
                {
                    color: [$($color_atch:ident),*],
                    depth_stencil: {$($depth_atch:ident)*},
                    input: [$($input_atch:ident),*]$(,)*
                    $(resolve: [$($resolve_atch:ident),*])*$(,)*
                }
            ),*
        ]
    ) => ({
        use $crate::render_pass::RenderPass;

        let create_info = {
            #[allow(unused)]
            let mut attachment_num = 0;
            $(
                let $atch_name = attachment_num;
                attachment_num += 1;
            )*

            #[allow(unused)]
            let mut layouts: Vec<(
                Option<$crate::image::ImageLayout>,
                Option<$crate::image::ImageLayout>
            )> = vec![(None, None); attachment_num as usize];

            let subpasses = vec![
                $({
                    let desc = $crate::render_pass::SubpassDescription {
                        color_attachments: vec![
                            $({
                                let layout = &mut layouts[$color_atch as usize];
                                layout.0 = layout.0.or(Some($crate::image::ImageLayout::ColorAttachmentOptimal));
                                layout.1 = Some($crate::image::ImageLayout::ColorAttachmentOptimal);

                                Some($crate::render_pass::AttachmentReference {
                                    attachment: $color_atch,
                                    layout: $crate::image::ImageLayout::ColorAttachmentOptimal,
                                    ..Default::default()
                                })
                            }),*
                        ],
                        depth_stencil_attachment: {
                            let depth: Option<$crate::render_pass::AttachmentReference> = None;
                            $(
                                let layout = &mut layouts[$depth_atch as usize];
                                layout.1 = Some($crate::image::ImageLayout::DepthStencilAttachmentOptimal);
                                layout.0 = layout.0.or(layout.1);

                                let depth = Some($crate::render_pass::AttachmentReference {
                                    attachment: $depth_atch,
                                    layout: $crate::image::ImageLayout::DepthStencilAttachmentOptimal,
                                    ..Default::default()
                                });
                            )*
                            depth
                        },
                        input_attachments: vec![
                            $({
                                let layout = &mut layouts[$input_atch as usize];
                                layout.1 = Some($crate::image::ImageLayout::ShaderReadOnlyOptimal);
                                layout.0 = layout.0.or(layout.1);

                                Some($crate::render_pass::AttachmentReference {
                                    attachment: $input_atch,
                                    layout: $crate::image::ImageLayout::ShaderReadOnlyOptimal,
                                    ..Default::default()
                                })
                            }),*
                        ],
                        resolve_attachments: vec![
                            $($({
                                let layout = &mut layouts[$resolve_atch as usize];
                                layout.1 = Some($crate::image::ImageLayout::TransferDstOptimal);
                                layout.0 = layout.0.or(layout.1);

                                Some($crate::render_pass::AttachmentReference {
                                    attachment: $resolve_atch,
                                    layout: $crate::image::ImageLayout::TransferDstOptimal,
                                    ..Default::default()
                                })
                            }),*)*
                        ],
                        preserve_attachments: (0 .. attachment_num).filter(|&a| {
                            $(if a == $color_atch { return false; })*
                            $(if a == $depth_atch { return false; })*
                            $(if a == $input_atch { return false; })*
                            $($(if a == $resolve_atch { return false; })*)*
                            true
                        }).collect(),
                        ..Default::default()
                    };

                    assert!(desc.resolve_attachments.is_empty() ||
                            desc.resolve_attachments.len() == desc.color_attachments.len());
                    desc
                }),*
            ];

            let dependencies: Vec<_> = (0..subpasses.len().saturating_sub(1) as u32)
                .map(|id| {
                    // TODO: correct values
                    let src_stages = $crate::sync::PipelineStages {
                        all_graphics: true,
                        ..$crate::sync::PipelineStages::empty()
                    };
                    let dst_stages = $crate::sync::PipelineStages {
                        all_graphics: true,
                        ..$crate::sync::PipelineStages::empty()
                    };
                    let src_access = $crate::sync::AccessFlags {
                        indirect_command_read: true,
                        index_read: true,
                        vertex_attribute_read: true,
                        uniform_read: true,
                        input_attachment_read: true,
                        shader_read: true,
                        shader_write: true,
                        color_attachment_read: true,
                        color_attachment_write: true,
                        depth_stencil_attachment_read: true,
                        depth_stencil_attachment_write: true,
                        memory_read: true,
                        memory_write: true,
                        ..$crate::sync::AccessFlags::empty()
                    };
                    let dst_access = $crate::sync::AccessFlags {
                        indirect_command_read: true,
                        index_read: true,
                        vertex_attribute_read: true,
                        uniform_read: true,
                        input_attachment_read: true,
                        shader_read: true,
                        shader_write: true,
                        color_attachment_read: true,
                        color_attachment_write: true,
                        depth_stencil_attachment_read: true,
                        depth_stencil_attachment_write: true,
                        memory_read: true,
                        memory_write: true,
                        ..$crate::sync::AccessFlags::empty()
                    };

                    $crate::render_pass::SubpassDependency {
                        src_subpass: id.into(),
                        dst_subpass: (id + 1).into(),
                        src_stages,
                        dst_stages,
                        src_access,
                        dst_access,
                        by_region: true,                      // TODO: correct values
                        ..Default::default()
                    }
                })
                .collect();

            let attachments = vec![
                $({
                    let layout = &mut layouts[$atch_name as usize];
                    $(layout.0 = Some($init_layout);)*
                    $(layout.1 = Some($final_layout);)*

                    $crate::render_pass::AttachmentDescription {
                        format: Some($format),
                        samples: $crate::image::SampleCount::try_from($samples).unwrap(),
                        load_op: $crate::render_pass::LoadOp::$load,
                        store_op: $crate::render_pass::StoreOp::$store,
                        stencil_load_op: $crate::render_pass::LoadOp::$load,
                        stencil_store_op: $crate::render_pass::StoreOp::$store,
                        initial_layout: layout.0.expect(
                            format!(
                                "Attachment {} is missing initial_layout, this is normally \
                                automatically determined but you can manually specify it for an individual \
                                attachment in the single_pass_renderpass! macro",
                                attachment_num
                            )
                            .as_ref(),
                        ),
                        final_layout: layout.1.expect(
                            format!(
                                "Attachment {} is missing final_layout, this is normally \
                                automatically determined but you can manually specify it for an individual \
                                attachment in the single_pass_renderpass! macro",
                                attachment_num
                            )
                            .as_ref(),
                        ),
                        ..Default::default()
                    }
                }),*
            ];

            $crate::render_pass::RenderPassCreateInfo {
                attachments,
                subpasses,
                dependencies,
                ..Default::default()
            }
        };

        RenderPass::new($device, create_info)
    });
}

#[cfg(test)]
mod tests {
    use crate::format::Format;

    #[test]
    fn single_pass_resolve() {
        let (device, _) = gfx_dev_and_queue!();
        let _ = single_pass_renderpass!(device,
            attachments: {
                a: {
                    load: Clear,
                    store: DontCare,
                    format: Format::R8G8B8A8_UNORM,
                    samples: 4,
                },
                b: {
                    load: DontCare,
                    store: Store,
                    format: Format::R8G8B8A8_UNORM,
                    samples: 1,
                }
            },
            pass: {
                color: [a],
                depth_stencil: {},
                resolve: [b],
            }
        )
        .unwrap();
    }
}
<|endoftext|>


<commit_before>use syn;
use quote;

pub fn generate_index_struct(ast: &syn::MacroInput) -> quote::Tokens {
    let ident = &ast.ident;
    let index_ident = syn::Ident::from(format!("{}Index", ident).to_string());
    let pipes_ident = syn::Ident::from(format!("{}Pipes", ident).to_string());

    let variant_data = if let syn::Body::Struct(ref variant_data) = ast.body {
        variant_data
    } else {
        panic!("derive(PerlinDocument) only implemented for Structs!");
    };

    let ext_id = external_id_field(ast);
    let external_id_param = external_id_param(ast);
    let add_external_id = add_external_id(ast);
    let create_external_ids = create_external_ids(ast);
    let pipeline_setters = set_pipelines(variant_data.fields(), ident);
    let run_query = run_query(ast);
    let field_matches = field_matches(variant_data.fields());
    quote!(

        pub struct #index_ident {
            documents: #ident,
            pipelines: #pipes_ident,
            query_pipeline: Option<QueryPipeline<#ident>>,
            base_path: PathBuf,
            doc_counter: DocId,
            #ext_id
        }

        impl #index_ident {
            pub fn create(base_path: PathBuf) -> Self {
                #index_ident {
                    documents: #ident::create(&base_path),
                    pipelines: #pipes_ident::default(),
                    query_pipeline: None,
                    base_path: base_path,
                    doc_counter: DocId::none(),
                    #create_external_ids
                }
            }

            pub fn commit(&mut self) {
                self.documents.commit();
            }

            pub fn add_document(&mut self, key_values: &[(Cow<str>, Cow<str>)] #external_id_param) {
                self.doc_counter.inc();
                let doc_id = self.doc_counter;

                for &(ref key, ref value) in key_values {
                    match key.as_ref() {
                        //"field_name" =>  self.pipelines.field_name(doc_id, &mut self.documents, value);
                        #(#field_matches,)*
                        _ => {
                           // panic!("#ident not found!")
                        }
                    }
                }
                #add_external_id
            }

            pub fn set_query_pipeline(&mut self, pipe: QueryPipeline<#ident>) {
                self.query_pipeline = Some(pipe);
            }

            #run_query

            //Pipeline setter
            //fn set_field_pipeline(&mut self, pipe: Pipeline<Type, Ident>)
            #(#pipeline_setters)*
        }
    )
}

fn run_query(ast: &syn::MacroInput) -> quote::Tokens {
    if let Some(ext_id_type) = get_external_id_type(&ast.attrs) {
        quote!{
            pub fn run_query<'a>(&'a self, query: &str) -> Box<Iterator<Item=#ext_id_type> +'a> {
                use perlin_core::index::posting::Posting;
                if let Some(ref query_pipe) = self.query_pipeline {
                    Box::new(query_pipe(&self.documents, query)
                        .map(move |Posting(doc_id)| {
                            if let Ok(index) = self.external_ids.binary_search_by_key(&doc_id, |&(d_id, _)| d_id) {
                                self.external_ids[index].1.clone()
                            } else {
                                panic!("DocId unknown!");
                            }
                        })) as Box<Iterator<Item=#ext_id_type>>
                } else {
                    panic!("Query Pipe not set!");
                }
            }
        }
    } else {
        quote!{
            pub fn run_query<'a>(&'a self, query: &str) -> Operand<'a> {
                if let Some(ref query_pipe) = self.query_pipeline {
                    query_pipe(&self.documents, query)
                } else {
                    panic!("Query Pipe not set!");
                }
            }
        }
    }
}

fn set_pipelines(fields: &[syn::Field], ident: &syn::Ident) -> Vec<quote::Tokens> {
    let mut result = Vec::new();
    for field in fields {
        let field_ident = &field.ident;
        let fn_ident = syn::Ident::from(format!("set_{}_pipeline", field_ident.clone().unwrap()).to_string());
        let ty = get_generics_from_field(&field.ty);
        result.push(quote!{
            pub fn #fn_ident(&mut self, pipe: Pipeline<#ty, #ident>) {
                self.pipelines.#field_ident = Some(pipe);
            }
        });
    }

    result
}

fn get_generics_from_field(field: &syn::Ty) -> quote::Tokens {
    if let &syn::Ty::Path(_, ref path) = field {
        for segment in &path.segments {
            if segment.ident == "Field" {
                if let syn::PathParameters::AngleBracketed(ref params) = segment.parameters {
                    let params = &params.types.first();
                    return quote!(#params);
                }
            }
        }
    }
    panic!("NO FIELD FOUND!");
}

fn field_matches(fields: &[syn::Field]) -> Vec<quote::Tokens> {
    let mut result = Vec::new();
    for field in fields {
        let ident = &field.ident;
        result.push(
            quote!{
                stringify!(#ident) => {
                    if let Some(ref pipeline) = self.pipelines.#ident {
                        pipeline(doc_id, &mut self.documents, value.as_ref());
                    } else {
                        //panic!("Tried to index field #ident without initialized pipeline!")
                    }
                }
            }
        );
    }
    result
}

fn create_external_ids(ast: &syn::MacroInput) -> quote::Tokens {
    if let Some(_) = get_external_id_type(&ast.attrs) {
        quote!{
            external_ids: Vec::new()
        }
    } else {
        quote!()
    }
}

fn add_external_id(ast: &syn::MacroInput) -> quote::Tokens {
    if let Some(_) = get_external_id_type(&ast.attrs) {
        quote!{
            self.external_ids.push((doc_id, external_id));
        }
    } else {
        quote!()
    }
}

fn external_id_param(ast: &syn::MacroInput) -> quote::Tokens {
    if let Some(ext_id) = get_external_id_type(&ast.attrs) {
        quote!(, external_id: #ext_id)
    } else {
        quote!()
    }
}

fn external_id_field(ast: &syn::MacroInput) -> quote::Tokens {
    if let Some(ext_id) = get_external_id_type(&ast.attrs) {
        quote!(external_ids: Vec<(DocId, #ext_id)>,)
    } else {
        quote!()
    }
}

fn get_external_id_type(attributes: &[syn::Attribute]) -> Option<syn::NestedMetaItem> {
    for attribute in attributes {
        if attribute.name() == "ExternalId" {
            if let syn::MetaItem::List(_, ref nested_items) = attribute.value {
                return Some(nested_items[0].clone());
            }
        }
    }
    None
}
<commit_msg>removed base_path from index structs<commit_after>use syn;
use quote;

pub fn generate_index_struct(ast: &syn::MacroInput) -> quote::Tokens {
    let ident = &ast.ident;
    let index_ident = syn::Ident::from(format!("{}Index", ident).to_string());
    let pipes_ident = syn::Ident::from(format!("{}Pipes", ident).to_string());

    let variant_data = if let syn::Body::Struct(ref variant_data) = ast.body {
        variant_data
    } else {
        panic!("derive(PerlinDocument) only implemented for Structs!");
    };

    let ext_id = external_id_field(ast);
    let external_id_param = external_id_param(ast);
    let add_external_id = add_external_id(ast);
    let create_external_ids = create_external_ids(ast);
    let pipeline_setters = set_pipelines(variant_data.fields(), ident);
    let run_query = run_query(ast);
    let field_matches = field_matches(variant_data.fields());
    quote!(

        pub struct #index_ident {
            documents: #ident,
            pipelines: #pipes_ident,
            query_pipeline: Option<QueryPipeline<#ident>>,
            doc_counter: DocId,
            #ext_id
        }

        impl #index_ident {
            pub fn create(base_path: PathBuf) -> Self {
                #index_ident {
                    documents: #ident::create(&base_path),
                    pipelines: #pipes_ident::default(),
                    query_pipeline: None,
                    doc_counter: DocId::none(),
                    #create_external_ids
                }
            }

            pub fn commit(&mut self) {
                self.documents.commit();
            }

            pub fn add_document(&mut self, key_values: &[(Cow<str>, Cow<str>)] #external_id_param) {
                self.doc_counter.inc();
                let doc_id = self.doc_counter;

                for &(ref key, ref value) in key_values {
                    match key.as_ref() {
                        //"field_name" =>  self.pipelines.field_name(doc_id, &mut self.documents, value);
                        #(#field_matches,)*
                        _ => {
                           // panic!("#ident not found!")
                        }
                    }
                }
                #add_external_id
            }

            pub fn set_query_pipeline(&mut self, pipe: QueryPipeline<#ident>) {
                self.query_pipeline = Some(pipe);
            }

            #run_query

            //Pipeline setter
            //fn set_field_pipeline(&mut self, pipe: Pipeline<Type, Ident>)
            #(#pipeline_setters)*
        }
    )
}

fn run_query(ast: &syn::MacroInput) -> quote::Tokens {
    if let Some(ext_id_type) = get_external_id_type(&ast.attrs) {
        quote!{
            pub fn run_query<'a>(&'a self, query: &str) -> Box<Iterator<Item=#ext_id_type> +'a> {
                use perlin_core::index::posting::Posting;
                if let Some(ref query_pipe) = self.query_pipeline {
                    Box::new(query_pipe(&self.documents, query)
                        .map(move |Posting(doc_id)| {
                            if let Ok(index) = self.external_ids.binary_search_by_key(&doc_id, |&(d_id, _)| d_id) {
                                self.external_ids[index].1.clone()
                            } else {
                                panic!("DocId unknown!");
                            }
                        })) as Box<Iterator<Item=#ext_id_type>>
                } else {
                    panic!("Query Pipe not set!");
                }
            }
        }
    } else {
        quote!{
            pub fn run_query<'a>(&'a self, query: &str) -> Operand<'a> {
                if let Some(ref query_pipe) = self.query_pipeline {
                    query_pipe(&self.documents, query)
                } else {
                    panic!("Query Pipe not set!");
                }
            }
        }
    }
}

fn set_pipelines(fields: &[syn::Field], ident: &syn::Ident) -> Vec<quote::Tokens> {
    let mut result = Vec::new();
    for field in fields {
        let field_ident = &field.ident;
        let fn_ident = syn::Ident::from(format!("set_{}_pipeline", field_ident.clone().unwrap()).to_string());
        let ty = get_generics_from_field(&field.ty);
        result.push(quote!{
            pub fn #fn_ident(&mut self, pipe: Pipeline<#ty, #ident>) {
                self.pipelines.#field_ident = Some(pipe);
            }
        });
    }

    result
}

fn get_generics_from_field(field: &syn::Ty) -> quote::Tokens {
    if let &syn::Ty::Path(_, ref path) = field {
        for segment in &path.segments {
            if segment.ident == "Field" {
                if let syn::PathParameters::AngleBracketed(ref params) = segment.parameters {
                    let params = &params.types.first();
                    return quote!(#params);
                }
            }
        }
    }
    panic!("NO FIELD FOUND!");
}

fn field_matches(fields: &[syn::Field]) -> Vec<quote::Tokens> {
    let mut result = Vec::new();
    for field in fields {
        let ident = &field.ident;
        result.push(
            quote!{
                stringify!(#ident) => {
                    if let Some(ref pipeline) = self.pipelines.#ident {
                        pipeline(doc_id, &mut self.documents, value.as_ref());
                    } else {
                        //panic!("Tried to index field #ident without initialized pipeline!")
                    }
                }
            }
        );
    }
    result
}

fn create_external_ids(ast: &syn::MacroInput) -> quote::Tokens {
    if let Some(_) = get_external_id_type(&ast.attrs) {
        quote!{
            external_ids: Vec::new()
        }
    } else {
        quote!()
    }
}

fn add_external_id(ast: &syn::MacroInput) -> quote::Tokens {
    if let Some(_) = get_external_id_type(&ast.attrs) {
        quote!{
            self.external_ids.push((doc_id, external_id));
        }
    } else {
        quote!()
    }
}

fn external_id_param(ast: &syn::MacroInput) -> quote::Tokens {
    if let Some(ext_id) = get_external_id_type(&ast.attrs) {
        quote!(, external_id: #ext_id)
    } else {
        quote!()
    }
}

fn external_id_field(ast: &syn::MacroInput) -> quote::Tokens {
    if let Some(ext_id) = get_external_id_type(&ast.attrs) {
        quote!(external_ids: Vec<(DocId, #ext_id)>,)
    } else {
        quote!()
    }
}

fn get_external_id_type(attributes: &[syn::Attribute]) -> Option<syn::NestedMetaItem> {
    for attribute in attributes {
        if attribute.name() == "ExternalId" {
            if let syn::MetaItem::List(_, ref nested_items) = attribute.value {
                return Some(nested_items[0].clone());
            }
        }
    }
    None
}
<|endoftext|>


<commit_before>extern crate rs_nes;
extern crate sdl2;

use rs_nes::cpu::*;
use rs_nes::input::{Button, Input, InputBase};
use rs_nes::memory::Memory;
use rs_nes::memory::nes_memory::NesMemoryImpl;
use rs_nes::ppu::{Ppu, PpuImpl};
use rs_nes::rom::NesRom;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::PixelFormatEnum;
use std::env;
use std::rc::Rc;
use std::thread;
use std::time::{Duration, Instant};

const SCREEN_WIDTH: u32 = 256;
const SCREEN_HEIGHT: u32 = 240;

fn main() {
    // INIT NES
    let file = env::args().last().unwrap();
    let rom = Rc::new(Box::new(
        NesRom::read(format!("{}", file)).expect("Couldn't find rom file"),
    ));
    println!(
        "ROM Mapper: {} CHR banks: {} CHR size: {}",
        rom.mapper,
        rom.chr_rom_banks,
        rom.chr.len()
    );

    let ppu = PpuImpl::new(rom.clone());
    let input = InputBase::default();
    let mem = NesMemoryImpl::new(rom, ppu, input);
    let mut cpu = Cpu::new(mem);
    cpu.reset();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem
        .window("RS-NES!", SCREEN_WIDTH * 2, SCREEN_HEIGHT * 2)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window
        .renderer()
        .accelerated()
        .present_vsync()
        .build()
        .unwrap();

    let mut texture = renderer
        .create_texture_streaming(PixelFormatEnum::RGB24, SCREEN_WIDTH, SCREEN_HEIGHT)
        .unwrap();

    let mut event_pump = sdl_context.event_pump().unwrap();
    let mut accumulator = Duration::new(0, 0);
    let mut previous_clock = Instant::now();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. }
                | Event::KeyDown {
                    keycode: Some(Keycode::Escape),
                    ..
                } => break 'running,
                Event::KeyDown {
                    keycode: Some(keycode),
                    ..
                } => match keycode {
                    Keycode::W => cpu.memory.input().player1_press(Button::Up),
                    Keycode::A => cpu.memory.input().player1_press(Button::Left),
                    Keycode::S => cpu.memory.input().player1_press(Button::Down),
                    Keycode::D => cpu.memory.input().player1_press(Button::Right),
                    Keycode::LShift | Keycode::RShift => {
                        cpu.memory.input().player1_press(Button::Select)
                    }
                    Keycode::Return => cpu.memory.input().player1_press(Button::Start),
                    Keycode::J => cpu.memory.input().player1_press(Button::B),
                    Keycode::K => cpu.memory.input().player1_press(Button::A),
                    _ => (),
                },
                Event::KeyUp {
                    keycode: Some(keycode),
                    ..
                } => match keycode {
                    Keycode::W => cpu.memory.input().player1_release(Button::Up),
                    Keycode::A => cpu.memory.input().player1_release(Button::Left),
                    Keycode::S => cpu.memory.input().player1_release(Button::Down),
                    Keycode::D => cpu.memory.input().player1_release(Button::Right),
                    Keycode::LShift | Keycode::RShift => {
                        cpu.memory.input().player1_release(Button::Select)
                    }
                    Keycode::Return => cpu.memory.input().player1_release(Button::Start),
                    Keycode::J => cpu.memory.input().player1_release(Button::B),
                    Keycode::K => cpu.memory.input().player1_release(Button::A),
                    _ => (),
                },
                _ => (),
            }
        }

        let now = Instant::now();
        accumulator += now - previous_clock;
        previous_clock = now;

        let fixed_time_stamp = Duration::new(0, 16666667);
        while accumulator >= fixed_time_stamp {
            accumulator -= fixed_time_stamp;
            loop {
                if cpu.step() == Interrupt::Nmi {
                    let screen_buffer = &*cpu.memory.screen().screen_buffer;
                    texture
                        .update(None, screen_buffer, SCREEN_WIDTH as usize * 3)
                        .unwrap();
                    renderer.clear();
                    renderer.copy(&texture, None, None).unwrap();
                    renderer.present();
                    break;
                }
            }
        }
        thread::sleep(fixed_time_stamp - accumulator);
    }
}
<commit_msg>Frame timing logic should go before input loop<commit_after>extern crate rs_nes;
extern crate sdl2;

use rs_nes::cpu::*;
use rs_nes::input::{Button, Input, InputBase};
use rs_nes::memory::Memory;
use rs_nes::memory::nes_memory::NesMemoryImpl;
use rs_nes::ppu::{Ppu, PpuImpl};
use rs_nes::rom::NesRom;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::PixelFormatEnum;
use std::env;
use std::rc::Rc;
use std::thread;
use std::time::{Duration, Instant};

const SCREEN_WIDTH: u32 = 256;
const SCREEN_HEIGHT: u32 = 240;

fn main() {
    // INIT NES
    let file = env::args().last().unwrap();
    let rom = Rc::new(Box::new(
        NesRom::read(format!("{}", file)).expect("Couldn't find rom file"),
    ));
    println!(
        "ROM Mapper: {} CHR banks: {} CHR size: {}",
        rom.mapper,
        rom.chr_rom_banks,
        rom.chr.len()
    );

    let ppu = PpuImpl::new(rom.clone());
    let input = InputBase::default();
    let mem = NesMemoryImpl::new(rom, ppu, input);
    let mut cpu = Cpu::new(mem);
    cpu.reset();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem
        .window("RS-NES!", SCREEN_WIDTH * 2, SCREEN_HEIGHT * 2)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window
        .renderer()
        .accelerated()
        .present_vsync()
        .build()
        .unwrap();

    let mut texture = renderer
        .create_texture_streaming(PixelFormatEnum::RGB24, SCREEN_WIDTH, SCREEN_HEIGHT)
        .unwrap();

    let mut event_pump = sdl_context.event_pump().unwrap();
    let mut accumulator = Duration::new(0, 0);
    let mut previous_clock = Instant::now();
    let fixed_time_stamp = Duration::new(0, 16666667);

    'running: loop {
        let now = Instant::now();
        accumulator += now - previous_clock;
        previous_clock = now;

        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. }
                | Event::KeyDown {
                    keycode: Some(Keycode::Escape),
                    ..
                } => break 'running,
                Event::KeyDown {
                    keycode: Some(keycode),
                    ..
                } => match keycode {
                    Keycode::W => cpu.memory.input().player1_press(Button::Up),
                    Keycode::A => cpu.memory.input().player1_press(Button::Left),
                    Keycode::S => cpu.memory.input().player1_press(Button::Down),
                    Keycode::D => cpu.memory.input().player1_press(Button::Right),
                    Keycode::LShift | Keycode::RShift => {
                        cpu.memory.input().player1_press(Button::Select)
                    }
                    Keycode::Return => cpu.memory.input().player1_press(Button::Start),
                    Keycode::J => cpu.memory.input().player1_press(Button::B),
                    Keycode::K => cpu.memory.input().player1_press(Button::A),
                    _ => (),
                },
                Event::KeyUp {
                    keycode: Some(keycode),
                    ..
                } => match keycode {
                    Keycode::W => cpu.memory.input().player1_release(Button::Up),
                    Keycode::A => cpu.memory.input().player1_release(Button::Left),
                    Keycode::S => cpu.memory.input().player1_release(Button::Down),
                    Keycode::D => cpu.memory.input().player1_release(Button::Right),
                    Keycode::LShift | Keycode::RShift => {
                        cpu.memory.input().player1_release(Button::Select)
                    }
                    Keycode::Return => cpu.memory.input().player1_release(Button::Start),
                    Keycode::J => cpu.memory.input().player1_release(Button::B),
                    Keycode::K => cpu.memory.input().player1_release(Button::A),
                    _ => (),
                },
                _ => (),
            }
        }

        while accumulator >= fixed_time_stamp {
            accumulator -= fixed_time_stamp;
            loop {
                if cpu.step() == Interrupt::Nmi {
                    let screen_buffer = &*cpu.memory.screen().screen_buffer;
                    texture
                        .update(None, screen_buffer, SCREEN_WIDTH as usize * 3)
                        .unwrap();
                    renderer.clear();
                    renderer.copy(&texture, None, None).unwrap();
                    renderer.present();
                    break;
                }
            }
        }
        thread::sleep(fixed_time_stamp - accumulator);
    }
}
<|endoftext|>


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

use bstr::{BString, ByteVec};
use regex_automata::dense;

use crate::{util, Error};

pub fn run(matches: &clap::ArgMatches) -> Result<(), Error> {
    Args::new(matches).and_then(|args| args.run())
}

#[derive(Debug)]
struct Args {
    input: PathBuf,
    regex: String,
    outputs: bool,
    start: Option<BString>,
    end: Option<BString>,
}

impl Args {
    fn new(m: &clap::ArgMatches) -> Result<Args, Error> {
        Ok(Args {
            input: m.value_of_os("input").map(PathBuf::from).unwrap(),
            regex: m
                .value_of_os("regex")
                .map(|v| v.to_string_lossy().into_owned())
                .unwrap(),
            outputs: m.is_present("outputs"),
            start: m
                .value_of_os("start")
                .map(|v| Vec::from_os_str_lossy(v).into_owned().into()),
            end: m
                .value_of_os("end")
                .map(|v| Vec::from_os_str_lossy(v).into_owned().into()),
        })
    }

    fn run(&self) -> Result<(), Error> {
        let fst = unsafe { util::mmap_fst(&self.input)? };
        let dense_dfa = dense::Builder::new()
            .anchored(true)
            .byte_classes(true)
            .premultiply(true)
            .build(&self.regex)?;
        let dfa = match dense_dfa {
            dense::DenseDFA::PremultipliedByteClass(dfa) => dfa,
            _ => unreachable!(),
        };
        let mut q = fst.search(&dfa);
        if let Some(ref start) = self.start {
            q = q.ge(start);
        }
        if let Some(ref end) = self.end {
            q = q.le(end);
        }
        util::print_stream(io::BufWriter::new(io::stdout()), self.outputs, q)
    }
}
<commit_msg>fst-bin: add knobs for reverse and minimization<commit_after>use std::io;
use std::path::PathBuf;

use bstr::{BString, ByteVec};
use regex_automata::dense;

use crate::{util, Error};

pub fn run(matches: &clap::ArgMatches) -> Result<(), Error> {
    Args::new(matches).and_then(|args| args.run())
}

#[derive(Debug)]
struct Args {
    input: PathBuf,
    regex: String,
    outputs: bool,
    start: Option<BString>,
    end: Option<BString>,
}

impl Args {
    fn new(m: &clap::ArgMatches) -> Result<Args, Error> {
        Ok(Args {
            input: m.value_of_os("input").map(PathBuf::from).unwrap(),
            regex: m
                .value_of_os("regex")
                .map(|v| v.to_string_lossy().into_owned())
                .unwrap(),
            outputs: m.is_present("outputs"),
            start: m
                .value_of_os("start")
                .map(|v| Vec::from_os_str_lossy(v).into_owned().into()),
            end: m
                .value_of_os("end")
                .map(|v| Vec::from_os_str_lossy(v).into_owned().into()),
        })
    }

    fn run(&self) -> Result<(), Error> {
        let reverse =
            std::env::var("FST_BIN_DFA_REVERSE").map_or(false, |v| v == "1");
        let minimize =
            std::env::var("FST_BIN_DFA_MINIMIZE").map_or(false, |v| v == "1");
        let fst = unsafe { util::mmap_fst(&self.input)? };
        let dense_dfa = dense::Builder::new()
            .anchored(true)
            .minimize(minimize)
            .byte_classes(true)
            .premultiply(true)
            .reverse(reverse)
            .build(&self.regex)?;
        let dfa = match dense_dfa {
            dense::DenseDFA::PremultipliedByteClass(dfa) => dfa,
            _ => unreachable!(),
        };
        let mut q = fst.search(&dfa);
        if let Some(ref start) = self.start {
            q = q.ge(start);
        }
        if let Some(ref end) = self.end {
            q = q.le(end);
        }
        util::print_stream(io::BufWriter::new(io::stdout()), self.outputs, q)
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate egl;
#[macro_use] extern crate log;
extern crate servo;
extern crate smallvec;

use egl::egl::EGLContext;
use egl::egl::EGLDisplay;
use egl::egl::EGLSurface;
use egl::egl::MakeCurrent;
use egl::egl::SwapBuffers;
use egl::eglext::eglGetProcAddress;
use servo::BrowserId;
use servo::Servo;
use servo::compositing::windowing::AnimationState;
use servo::compositing::windowing::EmbedderCoordinates;
use servo::compositing::windowing::MouseWindowEvent;
use servo::compositing::windowing::WindowEvent;
use servo::compositing::windowing::WindowMethods;
use servo::embedder_traits::EmbedderMsg;
use servo::embedder_traits::EventLoopWaker;
use servo::embedder_traits::resources::Resource;
use servo::embedder_traits::resources::ResourceReaderMethods;
use servo::euclid::TypedPoint2D;
use servo::euclid::TypedRect;
use servo::euclid::TypedScale;
use servo::euclid::TypedSize2D;
use servo::gl;
use servo::gl::Gl;
use servo::gl::GlesFns;
use servo::msg::constellation_msg::TraversalDirection;
use servo::script_traits::MouseButton;
use servo::servo_url::ServoUrl;
use servo::webrender_api::DevicePoint;
use smallvec::SmallVec;
use std::ffi::CStr;
use std::ffi::CString;
use std::io::Write;
use std::os::raw::c_char;
use std::os::raw::c_void;
use std::path::PathBuf;
use std::rc::Rc;
use std::thread;
use std::time::Duration;
use std::time::Instant;

#[repr(u32)]
pub enum MLLogLevel {
    Fatal = 0,
    Error = 1,
    Warning = 2,
    Info = 3,
    Debug = 4,
    Verbose = 5,
}

#[repr(transparent)]
pub struct MLLogger(extern "C" fn (MLLogLevel, *const c_char));

#[repr(transparent)]
pub struct MLHistoryUpdate(extern "C" fn (MLApp, bool, *const c_char, bool));

#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct MLApp(*mut c_void);

const LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info;

#[no_mangle]
pub unsafe extern "C" fn init_servo(ctxt: EGLContext,
                                    surf: EGLSurface,
                                    disp: EGLDisplay,
                                    app: MLApp,
                                    logger: MLLogger,
                                    history_update: MLHistoryUpdate,
                                    url: *const c_char,
                                    width: u32,
                                    height: u32,
                                    hidpi: f32) -> *mut ServoInstance
{
    // Servo initialization goes here!
    servo::embedder_traits::resources::set(Box::new(ResourceReaderInstance::new()));
    let _ = log::set_boxed_logger(Box::new(logger));
    log::set_max_level(LOG_LEVEL);
    let gl = GlesFns::load_with(|symbol| {
        let cstr = CString::new(symbol).expect("Failed to convert GL symbol to a char*");
        eglGetProcAddress(cstr.as_ptr() as _) as _
    });

    info!("OpenGL version {}", gl.get_string(gl::VERSION));
    let window = Rc::new(WindowInstance {
        ctxt: ctxt,
        surf: surf,
        disp: disp,
        gl: gl,
        width: width,
        height: height,
        hidpi: hidpi,
    });

    info!("Starting servo");
    let mut servo = Servo::new(window);
    let browser_id = BrowserId::new();

    let blank_url = ServoUrl::parse("about:blank").expect("Failed to parse about:blank!");
    let url = CStr::from_ptr(url).to_str().unwrap_or("about:blank");
    let url = ServoUrl::parse(url).unwrap_or(blank_url);
    servo.handle_events(vec![
        WindowEvent::NewBrowser(url, browser_id),
    ]);

    let result = Box::new(ServoInstance {
        app: app,
        browser_id: browser_id,
        history_update: history_update,
        servo: servo,
    });
    Box::into_raw(result)
}

#[no_mangle]
pub unsafe extern "C" fn heartbeat_servo(servo: *mut ServoInstance) {
    // Servo heartbeat goes here!
    if let Some(servo) = servo.as_mut() {
        servo.servo.handle_events(vec![]);
        for ((_browser_id, event)) in servo.servo.get_events() {
            match event {
                // Respond to any messages with a response channel
                // to avoid deadlocking the constellation
                EmbedderMsg::AllowNavigation(_url, sender) => {
                    let _ = sender.send(true);
                },
                EmbedderMsg::GetSelectedBluetoothDevice(_, sender) => {
                    let _ = sender.send(None);
                },
                EmbedderMsg::AllowUnload(sender) => {
                    let _ = sender.send(true);
                },
                EmbedderMsg::Alert(_, sender) => {
                    let _ = sender.send(());
                },
                EmbedderMsg::AllowOpeningBrowser(sender) => {
                    let _ = sender.send(false);
                },
                // Update the history UI
                EmbedderMsg::HistoryChanged(urls, index) => {
                    if let Some(url) = urls.get(index) {
                        if let Ok(cstr) = CString::new(url.as_str()) {
                            let can_go_back = index > 0;
                            let can_go_fwd = (index + 1) < urls.len();
                            (servo.history_update.0)(servo.app, can_go_back, cstr.as_ptr(), can_go_fwd);
                        }
                    }
                },
                // Ignore most messages for now
                EmbedderMsg::ChangePageTitle(..) |
                EmbedderMsg::BrowserCreated(..) |
                EmbedderMsg::LoadStart |
                EmbedderMsg::LoadComplete |
                EmbedderMsg::CloseBrowser |
                EmbedderMsg::Status(..) |
                EmbedderMsg::SelectFiles(..) |
                EmbedderMsg::MoveTo(..) |
                EmbedderMsg::ResizeTo(..) |
                EmbedderMsg::Keyboard(..) |
                EmbedderMsg::SetCursor(..) |
                EmbedderMsg::NewFavicon(..) |
                EmbedderMsg::HeadParsed |
                EmbedderMsg::SetFullscreenState(..) |
                EmbedderMsg::ShowIME(..) |
                EmbedderMsg::HideIME |
                EmbedderMsg::Shutdown |
                EmbedderMsg::Panic(..) => {},
            }
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn cursor_servo(servo: *mut ServoInstance, x: f32, y: f32, trigger: bool) {
    // Servo was triggered
    if let Some(servo) = servo.as_mut() {
        let point = DevicePoint::new(x, y);
        let window_event = if trigger {
            WindowEvent::MouseWindowEventClass(MouseWindowEvent::Click(MouseButton::Left, point))
        } else {
            WindowEvent::MouseWindowMoveEventClass(point)
        };
        servo.servo.handle_events(vec![window_event]);
    }
}

#[no_mangle]
pub unsafe extern "C" fn traverse_servo(servo: *mut ServoInstance, delta: i32) {
    // Traverse the session history
    if let Some(servo) = servo.as_mut() {
        let window_event = if delta == 0 {
            WindowEvent::Reload(servo.browser_id)
        } else if delta < 0 {
            WindowEvent::Navigation(servo.browser_id, TraversalDirection::Back(-delta as usize))
        } else {
            WindowEvent::Navigation(servo.browser_id, TraversalDirection::Forward(delta as usize))
        };
        servo.servo.handle_events(vec![window_event]);
    }
}

#[no_mangle]
pub unsafe extern "C" fn navigate_servo(servo: *mut ServoInstance, text: *const c_char) {
    if let Some(servo) = servo.as_mut() {
        let text = CStr::from_ptr(text).to_str().expect("Failed to convert text to UTF-8");
        let url = ServoUrl::parse(text).unwrap_or_else(|_| {
            let mut search = ServoUrl::parse("http://google.com/search")
               .expect("Failed to parse search URL")
               .into_url();
            search.query_pairs_mut().append_pair("q", text);
            ServoUrl::from_url(search)
        });
        let window_event = WindowEvent::LoadUrl(servo.browser_id, url);
        servo.servo.handle_events(vec![window_event]);
    }
}

// Some magic numbers for shutdown
const SHUTDOWN_DURATION: Duration = Duration::from_secs(10);
const SHUTDOWN_POLL_INTERVAL: Duration = Duration::from_millis(100);

#[no_mangle]
pub unsafe extern "C" fn discard_servo(servo: *mut ServoInstance) {
    if let Some(servo) = servo.as_mut() {
        let mut servo = Box::from_raw(servo);
        let finish = Instant::now() + SHUTDOWN_DURATION;
        servo.servo.handle_events(vec![WindowEvent::Quit]);
        'outer: loop {
            for (_, msg) in servo.servo.get_events() {
                if let EmbedderMsg::Shutdown = msg {
                    break 'outer;
                }
            }
            if Instant::now() > finish {
	       warn!("Incomplete shutdown.");
               break 'outer;
	    }
            thread::sleep(SHUTDOWN_POLL_INTERVAL);
            servo.servo.handle_events(vec![]);
        }
        servo.servo.deinit();
    }
}

pub struct ServoInstance {
    app: MLApp,
    browser_id: BrowserId,
    history_update: MLHistoryUpdate,
    servo: Servo<WindowInstance>,
}

struct WindowInstance {
    ctxt: EGLContext,
    surf: EGLSurface,
    disp: EGLDisplay,
    gl: Rc<Gl>,
    width: u32,
    height: u32,
    hidpi: f32,
}

impl WindowMethods for WindowInstance {
    fn present(&self) {
        SwapBuffers(self.disp, self.surf);
    }

    fn prepare_for_composite(&self) -> bool {
        MakeCurrent(self.disp, self.surf, self.surf, self.ctxt);
        self.gl.viewport(0, 0, self.width as i32, self.height as i32);
        true
    }

    fn gl(&self) -> Rc<Gl> {
        self.gl.clone()
    }

    fn create_event_loop_waker(&self) -> Box<EventLoopWaker> {
        Box::new(EventLoopWakerInstance::new())
    }

    fn get_coordinates(&self) -> EmbedderCoordinates {
        EmbedderCoordinates {
            hidpi_factor: TypedScale::new(self.hidpi),
            screen: TypedSize2D::new(self.width, self.height),
            screen_avail: TypedSize2D::new(self.width, self.height),
            window: (TypedSize2D::new(self.width, self.height), TypedPoint2D::new(0, 0)),
            framebuffer: TypedSize2D::new(self.width, self.height),
            viewport: TypedRect::new(TypedPoint2D::new(0, 0), TypedSize2D::new(self.width, self.height)),
        }
    }

    fn set_animation_state(&self, _state: AnimationState) {
    }
}

struct EventLoopWakerInstance;

impl EventLoopWakerInstance {
    fn new() -> EventLoopWakerInstance {
        EventLoopWakerInstance
    }
}

impl EventLoopWaker for EventLoopWakerInstance {
    fn clone(&self) -> Box<EventLoopWaker + Send> {
        Box::new(EventLoopWakerInstance)
    }

    fn wake(&self) {
    }
}

struct ResourceReaderInstance;

impl ResourceReaderInstance {
    fn new() -> ResourceReaderInstance {
        ResourceReaderInstance
    }
}

impl ResourceReaderMethods for ResourceReaderInstance {
    fn read(&self, res: Resource) -> Vec<u8> {
        Vec::from(match res {
            Resource::Preferences => &include_bytes!("../../../resources/prefs.json")[..],
            Resource::HstsPreloadList => &include_bytes!("../../../resources/hsts_preload.json")[..],
            Resource::SSLCertificates => &include_bytes!("../../../resources/certs")[..],
            Resource::BadCertHTML => &include_bytes!("../../../resources/badcert.html")[..],
            Resource::NetErrorHTML => &include_bytes!("../../../resources/neterror.html")[..],
            Resource::UserAgentCSS => &include_bytes!("../../../resources/user-agent.css")[..],
            Resource::ServoCSS => &include_bytes!("../../../resources/servo.css")[..],
            Resource::PresentationalHintsCSS => &include_bytes!("../../../resources/presentational-hints.css")[..],
            Resource::QuirksModeCSS => &include_bytes!("../../../resources/quirks-mode.css")[..],
            Resource::RippyPNG => &include_bytes!("../../../resources/rippy.png")[..],
            Resource::DomainList => &include_bytes!("../../../resources/public_domains.txt")[..],
            Resource::BluetoothBlocklist => &include_bytes!("../../../resources/gatt_blocklist.txt")[..],
        })
    }

    fn sandbox_access_files(&self) -> Vec<PathBuf> {
        vec![]
    }

    fn sandbox_access_files_dirs(&self) -> Vec<PathBuf> {
        vec![]
    }
}

impl log::Log for MLLogger {
    fn enabled(&self, metadata: &log::Metadata) -> bool {
        metadata.level() <= LOG_LEVEL
    }

    fn log(&self, record: &log::Record) {
        let lvl = match record.level() {
            log::Level::Error => MLLogLevel::Error,
            log::Level::Warn => MLLogLevel::Warning,
            log::Level::Info => MLLogLevel::Info,
            log::Level::Debug => MLLogLevel::Debug,
            log::Level::Trace => MLLogLevel::Verbose,
        };
        let mut msg = SmallVec::<[c_char; 128]>::new();
        write!(msg, "{}\0", record.args());
        (self.0)(lvl, &msg[0] as *const _ as *const _);
    }

    fn flush(&self) {}
}
<commit_msg>Argh tabs vs spaces<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate egl;
#[macro_use] extern crate log;
extern crate servo;
extern crate smallvec;

use egl::egl::EGLContext;
use egl::egl::EGLDisplay;
use egl::egl::EGLSurface;
use egl::egl::MakeCurrent;
use egl::egl::SwapBuffers;
use egl::eglext::eglGetProcAddress;
use servo::BrowserId;
use servo::Servo;
use servo::compositing::windowing::AnimationState;
use servo::compositing::windowing::EmbedderCoordinates;
use servo::compositing::windowing::MouseWindowEvent;
use servo::compositing::windowing::WindowEvent;
use servo::compositing::windowing::WindowMethods;
use servo::embedder_traits::EmbedderMsg;
use servo::embedder_traits::EventLoopWaker;
use servo::embedder_traits::resources::Resource;
use servo::embedder_traits::resources::ResourceReaderMethods;
use servo::euclid::TypedPoint2D;
use servo::euclid::TypedRect;
use servo::euclid::TypedScale;
use servo::euclid::TypedSize2D;
use servo::gl;
use servo::gl::Gl;
use servo::gl::GlesFns;
use servo::msg::constellation_msg::TraversalDirection;
use servo::script_traits::MouseButton;
use servo::servo_url::ServoUrl;
use servo::webrender_api::DevicePoint;
use smallvec::SmallVec;
use std::ffi::CStr;
use std::ffi::CString;
use std::io::Write;
use std::os::raw::c_char;
use std::os::raw::c_void;
use std::path::PathBuf;
use std::rc::Rc;
use std::thread;
use std::time::Duration;
use std::time::Instant;

#[repr(u32)]
pub enum MLLogLevel {
    Fatal = 0,
    Error = 1,
    Warning = 2,
    Info = 3,
    Debug = 4,
    Verbose = 5,
}

#[repr(transparent)]
pub struct MLLogger(extern "C" fn (MLLogLevel, *const c_char));

#[repr(transparent)]
pub struct MLHistoryUpdate(extern "C" fn (MLApp, bool, *const c_char, bool));

#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct MLApp(*mut c_void);

const LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info;

#[no_mangle]
pub unsafe extern "C" fn init_servo(ctxt: EGLContext,
                                    surf: EGLSurface,
                                    disp: EGLDisplay,
                                    app: MLApp,
                                    logger: MLLogger,
                                    history_update: MLHistoryUpdate,
                                    url: *const c_char,
                                    width: u32,
                                    height: u32,
                                    hidpi: f32) -> *mut ServoInstance
{
    // Servo initialization goes here!
    servo::embedder_traits::resources::set(Box::new(ResourceReaderInstance::new()));
    let _ = log::set_boxed_logger(Box::new(logger));
    log::set_max_level(LOG_LEVEL);
    let gl = GlesFns::load_with(|symbol| {
        let cstr = CString::new(symbol).expect("Failed to convert GL symbol to a char*");
        eglGetProcAddress(cstr.as_ptr() as _) as _
    });

    info!("OpenGL version {}", gl.get_string(gl::VERSION));
    let window = Rc::new(WindowInstance {
        ctxt: ctxt,
        surf: surf,
        disp: disp,
        gl: gl,
        width: width,
        height: height,
        hidpi: hidpi,
    });

    info!("Starting servo");
    let mut servo = Servo::new(window);
    let browser_id = BrowserId::new();

    let blank_url = ServoUrl::parse("about:blank").expect("Failed to parse about:blank!");
    let url = CStr::from_ptr(url).to_str().unwrap_or("about:blank");
    let url = ServoUrl::parse(url).unwrap_or(blank_url);
    servo.handle_events(vec![
        WindowEvent::NewBrowser(url, browser_id),
    ]);

    let result = Box::new(ServoInstance {
        app: app,
        browser_id: browser_id,
        history_update: history_update,
        servo: servo,
    });
    Box::into_raw(result)
}

#[no_mangle]
pub unsafe extern "C" fn heartbeat_servo(servo: *mut ServoInstance) {
    // Servo heartbeat goes here!
    if let Some(servo) = servo.as_mut() {
        servo.servo.handle_events(vec![]);
        for ((_browser_id, event)) in servo.servo.get_events() {
            match event {
                // Respond to any messages with a response channel
                // to avoid deadlocking the constellation
                EmbedderMsg::AllowNavigation(_url, sender) => {
                    let _ = sender.send(true);
                },
                EmbedderMsg::GetSelectedBluetoothDevice(_, sender) => {
                    let _ = sender.send(None);
                },
                EmbedderMsg::AllowUnload(sender) => {
                    let _ = sender.send(true);
                },
                EmbedderMsg::Alert(_, sender) => {
                    let _ = sender.send(());
                },
                EmbedderMsg::AllowOpeningBrowser(sender) => {
                    let _ = sender.send(false);
                },
                // Update the history UI
                EmbedderMsg::HistoryChanged(urls, index) => {
                    if let Some(url) = urls.get(index) {
                        if let Ok(cstr) = CString::new(url.as_str()) {
                            let can_go_back = index > 0;
                            let can_go_fwd = (index + 1) < urls.len();
                            (servo.history_update.0)(servo.app, can_go_back, cstr.as_ptr(), can_go_fwd);
                        }
                    }
                },
                // Ignore most messages for now
                EmbedderMsg::ChangePageTitle(..) |
                EmbedderMsg::BrowserCreated(..) |
                EmbedderMsg::LoadStart |
                EmbedderMsg::LoadComplete |
                EmbedderMsg::CloseBrowser |
                EmbedderMsg::Status(..) |
                EmbedderMsg::SelectFiles(..) |
                EmbedderMsg::MoveTo(..) |
                EmbedderMsg::ResizeTo(..) |
                EmbedderMsg::Keyboard(..) |
                EmbedderMsg::SetCursor(..) |
                EmbedderMsg::NewFavicon(..) |
                EmbedderMsg::HeadParsed |
                EmbedderMsg::SetFullscreenState(..) |
                EmbedderMsg::ShowIME(..) |
                EmbedderMsg::HideIME |
                EmbedderMsg::Shutdown |
                EmbedderMsg::Panic(..) => {},
            }
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn cursor_servo(servo: *mut ServoInstance, x: f32, y: f32, trigger: bool) {
    // Servo was triggered
    if let Some(servo) = servo.as_mut() {
        let point = DevicePoint::new(x, y);
        let window_event = if trigger {
            WindowEvent::MouseWindowEventClass(MouseWindowEvent::Click(MouseButton::Left, point))
        } else {
            WindowEvent::MouseWindowMoveEventClass(point)
        };
        servo.servo.handle_events(vec![window_event]);
    }
}

#[no_mangle]
pub unsafe extern "C" fn traverse_servo(servo: *mut ServoInstance, delta: i32) {
    // Traverse the session history
    if let Some(servo) = servo.as_mut() {
        let window_event = if delta == 0 {
            WindowEvent::Reload(servo.browser_id)
        } else if delta < 0 {
            WindowEvent::Navigation(servo.browser_id, TraversalDirection::Back(-delta as usize))
        } else {
            WindowEvent::Navigation(servo.browser_id, TraversalDirection::Forward(delta as usize))
        };
        servo.servo.handle_events(vec![window_event]);
    }
}

#[no_mangle]
pub unsafe extern "C" fn navigate_servo(servo: *mut ServoInstance, text: *const c_char) {
    if let Some(servo) = servo.as_mut() {
        let text = CStr::from_ptr(text).to_str().expect("Failed to convert text to UTF-8");
        let url = ServoUrl::parse(text).unwrap_or_else(|_| {
            let mut search = ServoUrl::parse("http://google.com/search")
               .expect("Failed to parse search URL")
               .into_url();
            search.query_pairs_mut().append_pair("q", text);
            ServoUrl::from_url(search)
        });
        let window_event = WindowEvent::LoadUrl(servo.browser_id, url);
        servo.servo.handle_events(vec![window_event]);
    }
}

// Some magic numbers for shutdown
const SHUTDOWN_DURATION: Duration = Duration::from_secs(10);
const SHUTDOWN_POLL_INTERVAL: Duration = Duration::from_millis(100);

#[no_mangle]
pub unsafe extern "C" fn discard_servo(servo: *mut ServoInstance) {
    if let Some(servo) = servo.as_mut() {
        let mut servo = Box::from_raw(servo);
        let finish = Instant::now() + SHUTDOWN_DURATION;
        servo.servo.handle_events(vec![WindowEvent::Quit]);
        'outer: loop {
            for (_, msg) in servo.servo.get_events() {
                if let EmbedderMsg::Shutdown = msg {
                    break 'outer;
                }
            }
            if Instant::now() > finish {
               warn!("Incomplete shutdown.");
               break 'outer;
            }
            thread::sleep(SHUTDOWN_POLL_INTERVAL);
            servo.servo.handle_events(vec![]);
        }
        servo.servo.deinit();
    }
}

pub struct ServoInstance {
    app: MLApp,
    browser_id: BrowserId,
    history_update: MLHistoryUpdate,
    servo: Servo<WindowInstance>,
}

struct WindowInstance {
    ctxt: EGLContext,
    surf: EGLSurface,
    disp: EGLDisplay,
    gl: Rc<Gl>,
    width: u32,
    height: u32,
    hidpi: f32,
}

impl WindowMethods for WindowInstance {
    fn present(&self) {
        SwapBuffers(self.disp, self.surf);
    }

    fn prepare_for_composite(&self) -> bool {
        MakeCurrent(self.disp, self.surf, self.surf, self.ctxt);
        self.gl.viewport(0, 0, self.width as i32, self.height as i32);
        true
    }

    fn gl(&self) -> Rc<Gl> {
        self.gl.clone()
    }

    fn create_event_loop_waker(&self) -> Box<EventLoopWaker> {
        Box::new(EventLoopWakerInstance::new())
    }

    fn get_coordinates(&self) -> EmbedderCoordinates {
        EmbedderCoordinates {
            hidpi_factor: TypedScale::new(self.hidpi),
            screen: TypedSize2D::new(self.width, self.height),
            screen_avail: TypedSize2D::new(self.width, self.height),
            window: (TypedSize2D::new(self.width, self.height), TypedPoint2D::new(0, 0)),
            framebuffer: TypedSize2D::new(self.width, self.height),
            viewport: TypedRect::new(TypedPoint2D::new(0, 0), TypedSize2D::new(self.width, self.height)),
        }
    }

    fn set_animation_state(&self, _state: AnimationState) {
    }
}

struct EventLoopWakerInstance;

impl EventLoopWakerInstance {
    fn new() -> EventLoopWakerInstance {
        EventLoopWakerInstance
    }
}

impl EventLoopWaker for EventLoopWakerInstance {
    fn clone(&self) -> Box<EventLoopWaker + Send> {
        Box::new(EventLoopWakerInstance)
    }

    fn wake(&self) {
    }
}

struct ResourceReaderInstance;

impl ResourceReaderInstance {
    fn new() -> ResourceReaderInstance {
        ResourceReaderInstance
    }
}

impl ResourceReaderMethods for ResourceReaderInstance {
    fn read(&self, res: Resource) -> Vec<u8> {
        Vec::from(match res {
            Resource::Preferences => &include_bytes!("../../../resources/prefs.json")[..],
            Resource::HstsPreloadList => &include_bytes!("../../../resources/hsts_preload.json")[..],
            Resource::SSLCertificates => &include_bytes!("../../../resources/certs")[..],
            Resource::BadCertHTML => &include_bytes!("../../../resources/badcert.html")[..],
            Resource::NetErrorHTML => &include_bytes!("../../../resources/neterror.html")[..],
            Resource::UserAgentCSS => &include_bytes!("../../../resources/user-agent.css")[..],
            Resource::ServoCSS => &include_bytes!("../../../resources/servo.css")[..],
            Resource::PresentationalHintsCSS => &include_bytes!("../../../resources/presentational-hints.css")[..],
            Resource::QuirksModeCSS => &include_bytes!("../../../resources/quirks-mode.css")[..],
            Resource::RippyPNG => &include_bytes!("../../../resources/rippy.png")[..],
            Resource::DomainList => &include_bytes!("../../../resources/public_domains.txt")[..],
            Resource::BluetoothBlocklist => &include_bytes!("../../../resources/gatt_blocklist.txt")[..],
        })
    }

    fn sandbox_access_files(&self) -> Vec<PathBuf> {
        vec![]
    }

    fn sandbox_access_files_dirs(&self) -> Vec<PathBuf> {
        vec![]
    }
}

impl log::Log for MLLogger {
    fn enabled(&self, metadata: &log::Metadata) -> bool {
        metadata.level() <= LOG_LEVEL
    }

    fn log(&self, record: &log::Record) {
        let lvl = match record.level() {
            log::Level::Error => MLLogLevel::Error,
            log::Level::Warn => MLLogLevel::Warning,
            log::Level::Info => MLLogLevel::Info,
            log::Level::Debug => MLLogLevel::Debug,
            log::Level::Trace => MLLogLevel::Verbose,
        };
        let mut msg = SmallVec::<[c_char; 128]>::new();
        write!(msg, "{}\0", record.args());
        (self.0)(lvl, &msg[0] as *const _ as *const _);
    }

    fn flush(&self) {}
}
<|endoftext|>


<commit_before>extern crate lalrpop_util;

pub mod json;
pub mod ast;

use std::io;
use std::fs::File;
use std::env;

fn read_to_toml(input: &mut io::Read) -> String {
    let mut json = String::new();
    let _ = input.read_to_string(&mut json);
    format!("{}", json::parse_json(&json).unwrap())
}

fn json_file_to_toml(fname: &str) -> String {
    let mut file = File::open(fname).unwrap();
    read_to_toml(&mut file)
}

fn main() {
    let args: Vec<String> = env::args().collect();

    match args.len() {
        1 => println!("{}", read_to_toml(&mut io::stdin())),
        2 => println!("{}", json_file_to_toml(&args[1])),
        _ => {
            println!("usage:
glstyleconv [jsonfilename]");
        }
    }
}

#[cfg(test)]
extern crate toml;

#[test]
fn json() {
    use lalrpop_util::ParseError;

    assert!(json::parse_json(r#"{"circle-radius": {"stops": [1, 0]}}"#).is_ok());
    assert!(json::parse_json(r#"{"circle-radius": {"property": "temperature","stops": [[{"zoom": 0, "value": 0}, 0],[{"zoom": 20, "value": 5}, 20]]}}"#).is_ok());
    assert!(json::parse_json(r#"{"string": "\u12345\\\"\r"}"#).is_ok());
    assert_eq!(json::parse_json(r#"{zoom: 0}"#), Err(ParseError::InvalidToken { location: 1 }));
}

#[test]
fn value_to_toml() {
    assert_eq!(json::parse_value("-1"), Ok(ast::Value::Integer(-1)));
    assert_eq!(json::parse_value("3.5"), Ok(ast::Value::Float(3.5)));
    assert_eq!(json::parse_value("2.5e10"), Ok(ast::Value::Float(2.5e10)));
    assert_eq!(json::parse_value("2e-10"), Ok(ast::Value::Float(2e-10)));
    assert_eq!(json::parse_value("true"), Ok(ast::Value::Boolean(true)));
    assert_eq!(json::parse_value("false"), Ok(ast::Value::Boolean(false)));
}

#[test]
fn json_to_toml() {
    let json = r#"[1,2,3]"#;
    let toml = "json = [1, 2, 3]\n";
    println!("{}", json::parse_json(json).unwrap());
    assert_eq!(format!("{}", json::parse_json(json).unwrap()), toml);
    assert!(toml::Parser::new(toml).parse().is_some());

    let json = r##"
        {
          "id": "water",
          "source": "mapbox-streets",
          "source-layer": "water",
          "type": "fill",
          "paint": {
            "fill-color": "#00ffff"
          }
        }"##;
    let toml = r##"id = "water"
source = "mapbox-streets"
source-layer = "water"
type = "fill"

[paint]
fill-color = "#00ffff"
"##;
    println!("{}", json::parse_json(json).unwrap());
    assert_eq!(format!("{}", json::parse_json(json).unwrap()), toml);
    assert!(toml::Parser::new(toml).parse().is_some());

    //top-level array shall be embedded in a table
    let json = r##"[
        {
          "id": "water",
          "source": "mapbox-streets",
          "source-layer": "water",
          "type": "fill",
          "paint": {
            "fill-color": "#00ffff"
          }
        }
    ]"##;
    let toml = r##"[[json]]
id = "water"
source = "mapbox-streets"
source-layer = "water"
type = "fill"

[json.paint]
fill-color = "#00ffff"
"##;
    println!("{}", json::parse_json(json).unwrap());
    assert_eq!(format!("{}", json::parse_json(json).unwrap()), toml);
    assert!(toml::Parser::new(toml).parse().is_some());

    let json = r#"{"circle-radius": {"stops": [[5, 1],[10, 2]]}}"#;
    let toml = r#"[circle-radius]
stops = [{ in = 5, out = 1 }, { in = 10, out = 2 }]
"#;

    let tomlparsed = json::parse_json(json).unwrap();
    println!("{}", tomlparsed);
    assert_eq!(format!("{}", tomlparsed), toml);
    //assert_eq!(tomlparsed, ast::Value::Table(toml::Parser::new(tomlshort).parse().unwrap()));

    let json = r#"{"circle-radius": {"property": "temperature","stops": [[{"zoom": 0, "value": 0}, 0],[{"zoom": 20, "value": 5}, 20]]}}"#;
    let toml = r#"[circle-radius]
property = "temperature"
stops = [{ in = { zoom = 0, value = 0 }, out = 0 }, { in = { zoom = 20, value = 5 }, out = 20 }]
"#;
    let tomlparsed = json::parse_json(json).unwrap();
    println!("{}", tomlparsed);
    assert_eq!(format!("{}", tomlparsed), toml);
    assert!(toml::Parser::new(toml).parse().is_some());
}

#[test]
fn mstudio_to_toml() {
    let toml = json_file_to_toml("testdata/bright-v9-cdn.json");
    println!("{}", toml);
    assert!(toml.contains(r##"[[layers]]
id = "background"
type = "background"
interactive = true

[layers.paint]
background-color = "#f8f4f0"

[[layers]]
id = "landuse_overlay_national_park"
type = "fill"
source = "mapbox"
source-layer = "landuse_overlay"
filter = ["==", "class", "national_park"]
interactive = true

[layers.paint]
fill-color = "#d8e8c8"
fill-opacity = 0.75

[layers.metadata]
"mapbox:group" = "1444849388993.3071"

[[layers]]
id = "landuse_park"
type = "fill"
source = "mapbox"
source-layer = "landuse"
filter = ["==", "class", "park"]
interactive = true
"##));

    assert!(toml.contains(r##"[[layers]]
interactive = true
filter = ["==", "scalerank", 1]
type = "symbol"
source = "mapbox"
id = "country_label_1"
source-layer = "country_label"

[layers.layout]
text-font = ["Open Sans Bold"]
text-field = "{name_en}"
text-max-width = 6.25
text-transform = "uppercase"

[layers.layout.text-size]
stops = [{ in = 1, out = 11 }, { in = 4, out = 17 }]
"##));

assert!(toml.contains(r##"
[layers.paint]
text-color = "#334"
text-halo-color = "rgba(255,255,255,0.8)"
text-halo-width = 2
text-halo-blur = 1
"##));

    assert!(toml.contains(r#"filter = [["all"], ["!=", "class", "river"], ["!=", "class", "stream"], ["!=", "class", "canal"]]"#));
}
<commit_msg>fill-translate test case<commit_after>extern crate lalrpop_util;

pub mod json;
pub mod ast;

use std::io;
use std::fs::File;
use std::env;

fn read_to_toml(input: &mut io::Read) -> String {
    let mut json = String::new();
    let _ = input.read_to_string(&mut json);
    format!("{}", json::parse_json(&json).unwrap())
}

fn json_file_to_toml(fname: &str) -> String {
    let mut file = File::open(fname).unwrap();
    read_to_toml(&mut file)
}

fn main() {
    let args: Vec<String> = env::args().collect();

    match args.len() {
        1 => println!("{}", read_to_toml(&mut io::stdin())),
        2 => println!("{}", json_file_to_toml(&args[1])),
        _ => {
            println!("usage:
glstyleconv [jsonfilename]");
        }
    }
}

#[cfg(test)]
extern crate toml;

#[test]
fn json() {
    use lalrpop_util::ParseError;

    assert!(json::parse_json(r#"{"circle-radius": {"stops": [1, 0]}}"#).is_ok());
    assert!(json::parse_json(r#"{"circle-radius": {"property": "temperature","stops": [[{"zoom": 0, "value": 0}, 0],[{"zoom": 20, "value": 5}, 20]]}}"#).is_ok());
    assert!(json::parse_json(r#"{"string": "\u12345\\\"\r"}"#).is_ok());
    assert_eq!(json::parse_json(r#"{zoom: 0}"#), Err(ParseError::InvalidToken { location: 1 }));
}

#[test]
fn value_to_toml() {
    assert_eq!(json::parse_value("-1"), Ok(ast::Value::Integer(-1)));
    assert_eq!(json::parse_value("3.5"), Ok(ast::Value::Float(3.5)));
    assert_eq!(json::parse_value("2.5e10"), Ok(ast::Value::Float(2.5e10)));
    assert_eq!(json::parse_value("2e-10"), Ok(ast::Value::Float(2e-10)));
    assert_eq!(json::parse_value("true"), Ok(ast::Value::Boolean(true)));
    assert_eq!(json::parse_value("false"), Ok(ast::Value::Boolean(false)));
}

#[test]
fn json_to_toml() {
    let json = r#"[1,2,3]"#;
    let toml = "json = [1, 2, 3]\n";
    println!("{}", json::parse_json(json).unwrap());
    assert_eq!(format!("{}", json::parse_json(json).unwrap()), toml);
    assert!(toml::Parser::new(toml).parse().is_some());

    let json = r##"
        {
          "id": "water",
          "source": "mapbox-streets",
          "source-layer": "water",
          "type": "fill",
          "paint": {
            "fill-color": "#00ffff"
          }
        }"##;
    let toml = r##"id = "water"
source = "mapbox-streets"
source-layer = "water"
type = "fill"

[paint]
fill-color = "#00ffff"
"##;
    println!("{}", json::parse_json(json).unwrap());
    assert_eq!(format!("{}", json::parse_json(json).unwrap()), toml);
    assert!(toml::Parser::new(toml).parse().is_some());

    //top-level array shall be embedded in a table
    let json = r##"[
        {
          "id": "water",
          "source": "mapbox-streets",
          "source-layer": "water",
          "type": "fill",
          "paint": {
            "fill-color": "#00ffff"
          }
        }
    ]"##;
    let toml = r##"[[json]]
id = "water"
source = "mapbox-streets"
source-layer = "water"
type = "fill"

[json.paint]
fill-color = "#00ffff"
"##;
    println!("{}", json::parse_json(json).unwrap());
    assert_eq!(format!("{}", json::parse_json(json).unwrap()), toml);
    assert!(toml::Parser::new(toml).parse().is_some());

    let json = r#"{"circle-radius": {"stops": [[5, 1],[10, 2]]}}"#;
    let toml = r#"[circle-radius]
stops = [{ in = 5, out = 1 }, { in = 10, out = 2 }]
"#;

    let tomlparsed = json::parse_json(json).unwrap();
    println!("{}", tomlparsed);
    assert_eq!(format!("{}", tomlparsed), toml);
    //assert_eq!(tomlparsed, ast::Value::Table(toml::Parser::new(tomlshort).parse().unwrap()));

    let json = r#"{"circle-radius": {"property": "temperature","stops": [[{"zoom": 0, "value": 0}, 0],[{"zoom": 20, "value": 5}, 20]]}}"#;
    let toml = r#"[circle-radius]
property = "temperature"
stops = [{ in = { zoom = 0, value = 0 }, out = 0 }, { in = { zoom = 20, value = 5 }, out = 20 }]
"#;
    let tomlparsed = json::parse_json(json).unwrap();
    println!("{}", tomlparsed);
    assert_eq!(format!("{}", tomlparsed), toml);
    assert!(toml::Parser::new(toml).parse().is_some());

    let json = r#"{"fill-translate": {"stops": [ [15, [0,0] ], [16, [-2,-2]] ], "base": 1}}"#;
    let toml = r#"[fill-translate]
base = 1
stops = [{ in = 15 }, { in = 16 }]
"#; //FIXME: "out" missing!
    let tomlparsed = json::parse_json(json).unwrap();
    println!("{}", tomlparsed);
    assert_eq!(format!("{}", tomlparsed), toml);
    assert!(toml::Parser::new(toml).parse().is_some());
}

#[test]
fn mstudio_to_toml() {
    let toml = json_file_to_toml("testdata/bright-v9-cdn.json");
    println!("{}", toml);
    assert!(toml.contains(r##"[[layers]]
id = "background"
type = "background"
interactive = true

[layers.paint]
background-color = "#f8f4f0"

[[layers]]
id = "landuse_overlay_national_park"
type = "fill"
source = "mapbox"
source-layer = "landuse_overlay"
filter = ["==", "class", "national_park"]
interactive = true

[layers.paint]
fill-color = "#d8e8c8"
fill-opacity = 0.75

[layers.metadata]
"mapbox:group" = "1444849388993.3071"

[[layers]]
id = "landuse_park"
type = "fill"
source = "mapbox"
source-layer = "landuse"
filter = ["==", "class", "park"]
interactive = true
"##));

    assert!(toml.contains(r##"[[layers]]
interactive = true
filter = ["==", "scalerank", 1]
type = "symbol"
source = "mapbox"
id = "country_label_1"
source-layer = "country_label"

[layers.layout]
text-font = ["Open Sans Bold"]
text-field = "{name_en}"
text-max-width = 6.25
text-transform = "uppercase"

[layers.layout.text-size]
stops = [{ in = 1, out = 11 }, { in = 4, out = 17 }]
"##));

assert!(toml.contains(r##"
[layers.paint]
text-color = "#334"
text-halo-color = "rgba(255,255,255,0.8)"
text-halo-width = 2
text-halo-blur = 1
"##));

    assert!(toml.contains(r#"filter = [["all"], ["!=", "class", "river"], ["!=", "class", "stream"], ["!=", "class", "canal"]]"#));
}
<|endoftext|>