<commit_before>// Copyright (c) 2018 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use clap;
use std::fs;
use std::io::Write;
use std::path::PathBuf;

use common::ui::{Status, UIWriter, UI};
use export_docker;
use export_docker::Result;
use export_k8s::{Manifest, ManifestJson};

use chartfile::ChartFile;
use deps::Deps;
use values::Values;

pub struct Chart<'a> {
    chartdir: PathBuf,
    chartfile: ChartFile,
    manifest_template: Option<ManifestJson>,
    values: Values,
    deps: Deps,
    ui: &'a mut UI,
}

impl<'a> Chart<'a> {
    pub fn new_for_cli_matches(ui: &'a mut UI, matches: &clap::ArgMatches) -> Result<Self> {
        let image = if !matches.is_present("NO_DOCKER_IMAGE") {
            export_docker::export_for_cli_matches(ui, &matches)?
        } else {
            None
        };
        let manifest = Manifest::new_from_cli_matches(ui, &matches, image)?;
        let chartfile = ChartFile::new_from_cli_matches(&matches, &manifest.pkg_ident)?;
        let deps = Deps::new_for_cli_matches(&matches);

        let mut chartdir = PathBuf::new();
        if let Some(o) = matches.value_of_os("OUTPUTDIR") {
            chartdir.push(o);
        }
        chartdir.push(&chartfile.name);

        Ok(Self::new_for_manifest(
            manifest, chartdir, chartfile, deps, ui,
        ))
    }

    fn new_for_manifest(
        manifest: Manifest,
        chartdir: PathBuf,
        chartfile: ChartFile,
        deps: Deps,
        ui: &'a mut UI,
    ) -> Self {
        let mut manifest_template = ManifestJson {
            value: json!({
            "metadata_name": "{{.Values.metadataName}}",
            "service_name": "{{.Values.serviceName}}",
            "image": "{{.Values.imageName}}",
            "count": "{{.Values.instanceCount}}",
            "service_topology": "{{.Values.serviceTopology}}",
            "service_group": manifest.service_group.clone().map(|_| "{{.Values.serviceGroup}}"),
            "config": manifest.config
                .clone()
                .map(|_| "{{.Values.config}}"),
            "ring_secret_name": manifest.ring_secret_name
                .clone()
                .map(|_| "{{.Values.ringSecretName}}"),
        }),
        };

        let mut values = Values::new();
        values.add_entry("metadataName", &manifest.metadata_name);
        values.add_entry("serviceName", &manifest.pkg_ident.name);
        values.add_entry("imageName", &manifest.image);
        values.add_entry("instanceCount", &manifest.count.to_string());
        values.add_entry("serviceTopology", &manifest.service_topology.to_string());
        if let Some(ref group) = manifest.service_group {
            values.add_entry("serviceGroup", group);
        }
        if let Some(ref config) = manifest.config {
            values.add_entry("config", config);
        }
        if let Some(ref name) = manifest.ring_secret_name {
            values.add_entry("ringSecretName", name);
        }

        let mut binds = Vec::new();
        let mut i = 0;
        for bind in &manifest.binds {
            let name_var = format!("bindName{}", i);
            let service_var = format!("bindService{}", i);
            let group_var = format!("bindGroup{}", i);
            i = i + 1;

            values.add_entry(&name_var, &bind.name);
            values.add_entry(&service_var, &bind.service_group.service());
            values.add_entry(&group_var, &bind.service_group.group());

            let json = json!({
                "name": format!("{{{{.Values.{}}}}}", name_var),
                "service": format!("{{{{.Values.{}}}}}", service_var),
                "group": format!("{{{{.Values.{}}}}}", group_var),
            });

            binds.push(json);
        }
        manifest_template.value["binds"] = json!(binds);

        Chart {
            chartdir: chartdir,
            chartfile: chartfile,
            manifest_template: Some(manifest_template),
            values: values,
            deps: deps,
            ui: ui,
        }
    }

    pub fn generate(mut self) -> Result<()> {
        self.ui.status(
            Status::Creating,
            format!("directory `{}`", self.chartdir.display()),
        )?;
        fs::create_dir_all(&self.chartdir)?;

        self.generate_chartfile()?;
        self.generate_values()?;
        self.generate_manifest_template()?;
        self.generate_deps()?;

        self.download_deps()
    }

    fn generate_chartfile(&mut self) -> Result<()> {
        let mut write = self.create_file("Chart.yaml")?;
        let out = self.chartfile.into_string()?;

        write.write(out.as_bytes())?;

        Ok(())
    }

    fn generate_manifest_template(&mut self) -> Result<()> {
        let mut path = self.chartdir.clone();
        path.push("templates");
        self.ui
            .status(Status::Creating, format!("directory `{}`", path.display()))?;
        fs::create_dir_all(&path)?;

        path.push("habitat.yaml");
        self.ui
            .status(Status::Creating, format!("file `{}`", path.display()))?;
        let mut write = fs::File::create(path)?;
        let out: String = self.manifest_template
            .take()
            .expect("generate_manifest_template() called more than once")
            .into();

        write.write(out.as_bytes())?;

        Ok(())
    }

    fn generate_values(&mut self) -> Result<()> {
        let mut write = self.create_file("values.yaml")?;
        self.values.generate(&mut write)?;

        Ok(())
    }

    fn generate_deps(&mut self) -> Result<()> {
        let mut write = self.create_file("requirements.yaml")?;
        self.deps.generate(&mut write)?;

        Ok(())
    }

    fn download_deps(&mut self) -> Result<()> {
        self.deps.download(&self.chartdir, self.ui)
    }

    fn create_file(&mut self, name: &str) -> Result<fs::File> {
        let mut path = self.chartdir.clone();
        path.push(name);
        self.ui
            .status(Status::Creating, format!("file `{}`", path.display()))?;

        fs::File::create(path).map_err(From::from)
    }
}
<commit_msg>pkg-export-helm: Avoid useless cloning<commit_after>// Copyright (c) 2018 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use clap;
use std::fs;
use std::io::Write;
use std::path::PathBuf;

use common::ui::{Status, UIWriter, UI};
use export_docker;
use export_docker::Result;
use export_k8s::{Manifest, ManifestJson};

use chartfile::ChartFile;
use deps::Deps;
use values::Values;

pub struct Chart<'a> {
    chartdir: PathBuf,
    chartfile: ChartFile,
    manifest_template: Option<ManifestJson>,
    values: Values,
    deps: Deps,
    ui: &'a mut UI,
}

impl<'a> Chart<'a> {
    pub fn new_for_cli_matches(ui: &'a mut UI, matches: &clap::ArgMatches) -> Result<Self> {
        let image = if !matches.is_present("NO_DOCKER_IMAGE") {
            export_docker::export_for_cli_matches(ui, &matches)?
        } else {
            None
        };
        let manifest = Manifest::new_from_cli_matches(ui, &matches, image)?;
        let chartfile = ChartFile::new_from_cli_matches(&matches, &manifest.pkg_ident)?;
        let deps = Deps::new_for_cli_matches(&matches);

        let mut chartdir = PathBuf::new();
        if let Some(o) = matches.value_of_os("OUTPUTDIR") {
            chartdir.push(o);
        }
        chartdir.push(&chartfile.name);

        Ok(Self::new_for_manifest(
            manifest, chartdir, chartfile, deps, ui,
        ))
    }

    fn new_for_manifest(
        manifest: Manifest,
        chartdir: PathBuf,
        chartfile: ChartFile,
        deps: Deps,
        ui: &'a mut UI,
    ) -> Self {
        let mut manifest_template = ManifestJson {
            value: json!({
            "metadata_name": "{{.Values.metadataName}}",
            "service_name": "{{.Values.serviceName}}",
            "image": "{{.Values.imageName}}",
            "count": "{{.Values.instanceCount}}",
            "service_topology": "{{.Values.serviceTopology}}",
            "service_group": manifest.service_group
                .as_ref()
                .map(|_| "{{.Values.serviceGroup}}"),
            "config": manifest.config
                .as_ref()
                .map(|_| "{{.Values.config}}"),
            "ring_secret_name": manifest.ring_secret_name
                .as_ref()
                .map(|_| "{{.Values.ringSecretName}}"),
            }),
        };

        let mut values = Values::new();
        values.add_entry("metadataName", &manifest.metadata_name);
        values.add_entry("serviceName", &manifest.pkg_ident.name);
        values.add_entry("imageName", &manifest.image);
        values.add_entry("instanceCount", &manifest.count.to_string());
        values.add_entry("serviceTopology", &manifest.service_topology.to_string());
        if let Some(ref group) = manifest.service_group {
            values.add_entry("serviceGroup", group);
        }
        if let Some(ref config) = manifest.config {
            values.add_entry("config", config);
        }
        if let Some(ref name) = manifest.ring_secret_name {
            values.add_entry("ringSecretName", name);
        }

        let mut binds = Vec::new();
        let mut i = 0;
        for bind in &manifest.binds {
            let name_var = format!("bindName{}", i);
            let service_var = format!("bindService{}", i);
            let group_var = format!("bindGroup{}", i);
            i = i + 1;

            values.add_entry(&name_var, &bind.name);
            values.add_entry(&service_var, &bind.service_group.service());
            values.add_entry(&group_var, &bind.service_group.group());

            let json = json!({
                "name": format!("{{{{.Values.{}}}}}", name_var),
                "service": format!("{{{{.Values.{}}}}}", service_var),
                "group": format!("{{{{.Values.{}}}}}", group_var),
            });

            binds.push(json);
        }
        manifest_template.value["binds"] = json!(binds);

        Chart {
            chartdir: chartdir,
            chartfile: chartfile,
            manifest_template: Some(manifest_template),
            values: values,
            deps: deps,
            ui: ui,
        }
    }

    pub fn generate(mut self) -> Result<()> {
        self.ui.status(
            Status::Creating,
            format!("directory `{}`", self.chartdir.display()),
        )?;
        fs::create_dir_all(&self.chartdir)?;

        self.generate_chartfile()?;
        self.generate_values()?;
        self.generate_manifest_template()?;
        self.generate_deps()?;

        self.download_deps()
    }

    fn generate_chartfile(&mut self) -> Result<()> {
        let mut write = self.create_file("Chart.yaml")?;
        let out = self.chartfile.into_string()?;

        write.write(out.as_bytes())?;

        Ok(())
    }

    fn generate_manifest_template(&mut self) -> Result<()> {
        let mut path = self.chartdir.clone();
        path.push("templates");
        self.ui
            .status(Status::Creating, format!("directory `{}`", path.display()))?;
        fs::create_dir_all(&path)?;

        path.push("habitat.yaml");
        self.ui
            .status(Status::Creating, format!("file `{}`", path.display()))?;
        let mut write = fs::File::create(path)?;
        let out: String = self.manifest_template
            .take()
            .expect("generate_manifest_template() called more than once")
            .into();

        write.write(out.as_bytes())?;

        Ok(())
    }

    fn generate_values(&mut self) -> Result<()> {
        let mut write = self.create_file("values.yaml")?;
        self.values.generate(&mut write)?;

        Ok(())
    }

    fn generate_deps(&mut self) -> Result<()> {
        let mut write = self.create_file("requirements.yaml")?;
        self.deps.generate(&mut write)?;

        Ok(())
    }

    fn download_deps(&mut self) -> Result<()> {
        self.deps.download(&self.chartdir, self.ui)
    }

    fn create_file(&mut self, name: &str) -> Result<fs::File> {
        let mut path = self.chartdir.clone();
        path.push(name);
        self.ui
            .status(Status::Creating, format!("file `{}`", path.display()))?;

        fs::File::create(path).map_err(From::from)
    }
}
<|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/. */

use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
use dom::bindings::codegen::Bindings::HTMLOptionElementBinding::HTMLOptionElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::conversions::{FromJSValConvertible, StringificationBehavior};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::element::Element;
use dom::htmlelement::HTMLElement;
use dom::htmliframeelement::HTMLIFrameElement;
use dom::htmlinputelement::HTMLInputElement;
use dom::htmloptionelement::HTMLOptionElement;
use dom::node::Node;
use dom::window::ScriptHelpers;
use euclid::point::Point2D;
use euclid::rect::Rect;
use euclid::size::Size2D;
use ipc_channel::ipc::IpcSender;
use js::jsapi::JSContext;
use js::jsapi::{HandleValue, RootedValue};
use js::jsval::UndefinedValue;
use msg::constellation_msg::{PipelineId, WindowSizeData};
use msg::webdriver_msg::{WebDriverFrameId, WebDriverJSError, WebDriverJSResult, WebDriverJSValue};
use page::Page;
use script_thread::get_page;
use std::rc::Rc;
use url::Url;
use util::str::DOMString;

fn find_node_by_unique_id(page: &Rc<Page>, pipeline: PipelineId, node_id: String) -> Option<Root<Node>> {
    let page = get_page(&*page, pipeline);
    let document = page.document();
    let node = document.upcast::<Node>();

    for candidate in node.traverse_preorder() {
        if candidate.get_unique_id() == node_id {
            return Some(candidate);
        }
    }

    None
}

#[allow(unsafe_code)]
pub unsafe fn jsval_to_webdriver(cx: *mut JSContext, val: HandleValue) -> WebDriverJSResult {
    if val.get().is_undefined() {
        Ok(WebDriverJSValue::Undefined)
    } else if val.get().is_boolean() {
        Ok(WebDriverJSValue::Boolean(val.get().to_boolean()))
    } else if val.get().is_double() || val.get().is_int32() {
        Ok(WebDriverJSValue::Number(FromJSValConvertible::from_jsval(cx, val, ()).unwrap()))
    } else if val.get().is_string() {
        //FIXME: use jsstring_to_str when jsval grows to_jsstring
        let string: DOMString = FromJSValConvertible::from_jsval(cx, val, StringificationBehavior::Default).unwrap();
        Ok(WebDriverJSValue::String(String::from(string)))
    } else if val.get().is_null() {
        Ok(WebDriverJSValue::Null)
    } else {
        Err(WebDriverJSError::UnknownType)
    }
}

#[allow(unsafe_code)]
pub fn handle_execute_script(page: &Rc<Page>,
                             pipeline: PipelineId,
                             eval: String,
                             reply: IpcSender<WebDriverJSResult>) {
    let page = get_page(&*page, pipeline);
    let window = page.window();
    let result = unsafe {
        let cx = window.get_cx();
        let mut rval = RootedValue::new(cx, UndefinedValue());
        window.evaluate_js_on_global_with_result(&eval, rval.handle_mut());
        jsval_to_webdriver(cx, rval.handle())
    };
    reply.send(result).unwrap();
}

pub fn handle_execute_async_script(page: &Rc<Page>,
                                   pipeline: PipelineId,
                                   eval: String,
                                   reply: IpcSender<WebDriverJSResult>) {
    let page = get_page(&*page, pipeline);
    let window = page.window();
    let cx = window.get_cx();
    window.set_webdriver_script_chan(Some(reply));
    let mut rval = RootedValue::new(cx, UndefinedValue());
    window.evaluate_js_on_global_with_result(&eval, rval.handle_mut());
}

pub fn handle_get_frame_id(page: &Rc<Page>,
                           pipeline: PipelineId,
                           webdriver_frame_id: WebDriverFrameId,
                           reply: IpcSender<Result<Option<PipelineId>, ()>>) {
    let window = match webdriver_frame_id {
        WebDriverFrameId::Short(_) => {
            // This isn't supported yet
            Ok(None)
        },
        WebDriverFrameId::Element(x) => {
            match find_node_by_unique_id(page, pipeline, x) {
                Some(ref node) => {
                    match node.downcast::<HTMLIFrameElement>() {
                        Some(ref elem) => Ok(elem.GetContentWindow()),
                        None => Err(())
                    }
                },
                None => Err(())
            }
        },
        WebDriverFrameId::Parent => {
            let window = page.window();
            Ok(window.parent())
        }
    };

    let frame_id = window.map(|x| x.map(|x| x.pipeline()));
    reply.send(frame_id).unwrap()
}

pub fn handle_find_element_css(page: &Rc<Page>, _pipeline: PipelineId, selector: String,
                               reply: IpcSender<Result<Option<String>, ()>>) {
    reply.send(match page.document().QuerySelector(DOMString::from(selector)) {
        Ok(node) => {
            Ok(node.map(|x| x.upcast::<Node>().get_unique_id()))
        }
        Err(_) => Err(())
    }).unwrap();
}

pub fn handle_find_elements_css(page: &Rc<Page>,
                                _pipeline: PipelineId,
                                selector: String,
                                reply: IpcSender<Result<Vec<String>, ()>>) {
    reply.send(match page.document().QuerySelectorAll(DOMString::from(selector)) {
        Ok(ref nodes) => {
            let mut result = Vec::with_capacity(nodes.Length() as usize);
            for i in 0..nodes.Length() {
                if let Some(ref node) = nodes.Item(i) {
                    result.push(node.get_unique_id());
                }
            }
            Ok(result)
        },
        Err(_) => {
            Err(())
        }
    }).unwrap();
}

pub fn handle_focus_element(page: &Rc<Page>,
                            pipeline: PipelineId,
                            element_id: String,
                            reply: IpcSender<Result<(), ()>>) {
    reply.send(match find_node_by_unique_id(page, pipeline, element_id) {
        Some(ref node) => {
            match node.downcast::<HTMLElement>() {
                Some(ref elem) => {
                    // Need a way to find if this actually succeeded
                    elem.Focus();
                    Ok(())
                }
                None => Err(())
            }
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_get_active_element(page: &Rc<Page>,
                                 _pipeline: PipelineId,
                                 reply: IpcSender<Option<String>>) {
    reply.send(page.document().GetActiveElement().map(
        |elem| elem.upcast::<Node>().get_unique_id())).unwrap();
}

pub fn handle_get_title(page: &Rc<Page>, _pipeline: PipelineId, reply: IpcSender<String>) {
    reply.send(String::from(page.document().Title())).unwrap();
}

pub fn handle_get_rect(page: &Rc<Page>,
                       pipeline: PipelineId,
                       element_id: String,
                       reply: IpcSender<Result<Rect<f64>, ()>>) {
    reply.send(match find_node_by_unique_id(&*page, pipeline, element_id) {
        Some(elem) => {
            // https://w3c.github.io/webdriver/webdriver-spec.html#dfn-calculate-the-absolute-position
            match elem.downcast::<HTMLElement>() {
                Some(html_elem) => {
                    // Step 1
                    let mut x = 0;
                    let mut y = 0;

                    let mut offset_parent = html_elem.GetOffsetParent();

                    // Step 2
                    while let Some(element) = offset_parent {
                        offset_parent = match element.downcast::<HTMLElement>() {
                            Some(elem) => {
                                x += elem.OffsetLeft();
                                y += elem.OffsetTop();
                                elem.GetOffsetParent()
                            },
                            None => None
                        };
                    }
                    // Step 3
                    Ok(Rect::new(Point2D::new(x as f64, y as f64),
                                 Size2D::new(html_elem.OffsetWidth() as f64,
                                             html_elem.OffsetHeight() as f64)))
                },
                None => Err(())
            }
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_get_text(page: &Rc<Page>,
                       pipeline: PipelineId,
                       node_id: String,
                       reply: IpcSender<Result<String, ()>>) {
    reply.send(match find_node_by_unique_id(&*page, pipeline, node_id) {
        Some(ref node) => {
            Ok(node.GetTextContent().map_or("".to_owned(), String::from))
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_get_name(page: &Rc<Page>,
                       pipeline: PipelineId,
                       node_id: String,
                       reply: IpcSender<Result<String, ()>>) {
    reply.send(match find_node_by_unique_id(&*page, pipeline, node_id) {
        Some(node) => {
            Ok(String::from(node.downcast::<Element>().unwrap().TagName()))
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_get_attribute(page: &Rc<Page>,
                            pipeline: PipelineId,
                            node_id: String,
                            name: String,
                            reply: IpcSender<Result<Option<String>, ()>>) {
    reply.send(match find_node_by_unique_id(&*page, pipeline, node_id) {
        Some(node) => {
            Ok(node.downcast::<Element>().unwrap().GetAttribute(DOMString::from(name))
               .map(String::from))
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_get_css(page: &Rc<Page>,
                      pipeline: PipelineId,
                      node_id: String,
                      name: String,
                      reply: IpcSender<Result<String, ()>>) {
    reply.send(match find_node_by_unique_id(&*page, pipeline, node_id) {
        Some(node) => {
            let window = page.window();
            let elem = node.downcast::<Element>().unwrap();
            Ok(String::from(
                window.GetComputedStyle(&elem, None).GetPropertyValue(DOMString::from(name))))
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_get_url(page: &Rc<Page>,
                      _pipeline: PipelineId,
                      reply: IpcSender<Url>) {
    let document = page.document();
    let url = document.url();
    reply.send((*url).clone()).unwrap();
}

pub fn handle_get_window_size(page: &Rc<Page>,
                              _pipeline: PipelineId,
                              reply: IpcSender<Option<WindowSizeData>>) {
    let window = page.window();
    let size = window.window_size();
    reply.send(size).unwrap();
}

pub fn handle_is_enabled(page: &Rc<Page>,
                         pipeline: PipelineId,
                         element_id: String,
                         reply: IpcSender<Result<bool, ()>>) {
    reply.send(match find_node_by_unique_id(page, pipeline, element_id) {
        Some(ref node) => {
            match node.downcast::<Element>() {
                Some(elem) => Ok(elem.get_enabled_state()),
                None => Err(())
            }
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_is_selected(page: &Rc<Page>,
                          pipeline: PipelineId,
                          element_id: String,
                          reply: IpcSender<Result<bool, ()>>) {
    reply.send(match find_node_by_unique_id(page, pipeline, element_id) {
        Some(ref node) => {
            if let Some(input_element) = node.downcast::<HTMLInputElement>() {
                Ok(input_element.Checked())
            }
            else if let Some(option_element) = node.downcast::<HTMLOptionElement>() {
                Ok(option_element.Selected())
            }
            else if let Some(_) = node.downcast::<HTMLElement>() {
                Ok(false) // regular elements are not selectable
            }
            else {
                Err(())
            }
        },
        None => Err(())
    }).unwrap();
}
<commit_msg>find_node_by_unique_id should use find<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/. */

use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
use dom::bindings::codegen::Bindings::HTMLOptionElementBinding::HTMLOptionElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::conversions::{FromJSValConvertible, StringificationBehavior};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::element::Element;
use dom::htmlelement::HTMLElement;
use dom::htmliframeelement::HTMLIFrameElement;
use dom::htmlinputelement::HTMLInputElement;
use dom::htmloptionelement::HTMLOptionElement;
use dom::node::Node;
use dom::window::ScriptHelpers;
use euclid::point::Point2D;
use euclid::rect::Rect;
use euclid::size::Size2D;
use ipc_channel::ipc::IpcSender;
use js::jsapi::JSContext;
use js::jsapi::{HandleValue, RootedValue};
use js::jsval::UndefinedValue;
use msg::constellation_msg::{PipelineId, WindowSizeData};
use msg::webdriver_msg::{WebDriverFrameId, WebDriverJSError, WebDriverJSResult, WebDriverJSValue};
use page::Page;
use script_thread::get_page;
use std::rc::Rc;
use url::Url;
use util::str::DOMString;

fn find_node_by_unique_id(page: &Rc<Page>, pipeline: PipelineId, node_id: String) -> Option<Root<Node>> {
    let page = get_page(&*page, pipeline);
    let document = page.document();
    document.upcast::<Node>().traverse_preorder().find(|candidate| candidate.get_unique_id() == node_id)
}

#[allow(unsafe_code)]
pub unsafe fn jsval_to_webdriver(cx: *mut JSContext, val: HandleValue) -> WebDriverJSResult {
    if val.get().is_undefined() {
        Ok(WebDriverJSValue::Undefined)
    } else if val.get().is_boolean() {
        Ok(WebDriverJSValue::Boolean(val.get().to_boolean()))
    } else if val.get().is_double() || val.get().is_int32() {
        Ok(WebDriverJSValue::Number(FromJSValConvertible::from_jsval(cx, val, ()).unwrap()))
    } else if val.get().is_string() {
        //FIXME: use jsstring_to_str when jsval grows to_jsstring
        let string: DOMString = FromJSValConvertible::from_jsval(cx, val, StringificationBehavior::Default).unwrap();
        Ok(WebDriverJSValue::String(String::from(string)))
    } else if val.get().is_null() {
        Ok(WebDriverJSValue::Null)
    } else {
        Err(WebDriverJSError::UnknownType)
    }
}

#[allow(unsafe_code)]
pub fn handle_execute_script(page: &Rc<Page>,
                             pipeline: PipelineId,
                             eval: String,
                             reply: IpcSender<WebDriverJSResult>) {
    let page = get_page(&*page, pipeline);
    let window = page.window();
    let result = unsafe {
        let cx = window.get_cx();
        let mut rval = RootedValue::new(cx, UndefinedValue());
        window.evaluate_js_on_global_with_result(&eval, rval.handle_mut());
        jsval_to_webdriver(cx, rval.handle())
    };
    reply.send(result).unwrap();
}

pub fn handle_execute_async_script(page: &Rc<Page>,
                                   pipeline: PipelineId,
                                   eval: String,
                                   reply: IpcSender<WebDriverJSResult>) {
    let page = get_page(&*page, pipeline);
    let window = page.window();
    let cx = window.get_cx();
    window.set_webdriver_script_chan(Some(reply));
    let mut rval = RootedValue::new(cx, UndefinedValue());
    window.evaluate_js_on_global_with_result(&eval, rval.handle_mut());
}

pub fn handle_get_frame_id(page: &Rc<Page>,
                           pipeline: PipelineId,
                           webdriver_frame_id: WebDriverFrameId,
                           reply: IpcSender<Result<Option<PipelineId>, ()>>) {
    let window = match webdriver_frame_id {
        WebDriverFrameId::Short(_) => {
            // This isn't supported yet
            Ok(None)
        },
        WebDriverFrameId::Element(x) => {
            match find_node_by_unique_id(page, pipeline, x) {
                Some(ref node) => {
                    match node.downcast::<HTMLIFrameElement>() {
                        Some(ref elem) => Ok(elem.GetContentWindow()),
                        None => Err(())
                    }
                },
                None => Err(())
            }
        },
        WebDriverFrameId::Parent => {
            let window = page.window();
            Ok(window.parent())
        }
    };

    let frame_id = window.map(|x| x.map(|x| x.pipeline()));
    reply.send(frame_id).unwrap()
}

pub fn handle_find_element_css(page: &Rc<Page>, _pipeline: PipelineId, selector: String,
                               reply: IpcSender<Result<Option<String>, ()>>) {
    reply.send(match page.document().QuerySelector(DOMString::from(selector)) {
        Ok(node) => {
            Ok(node.map(|x| x.upcast::<Node>().get_unique_id()))
        }
        Err(_) => Err(())
    }).unwrap();
}

pub fn handle_find_elements_css(page: &Rc<Page>,
                                _pipeline: PipelineId,
                                selector: String,
                                reply: IpcSender<Result<Vec<String>, ()>>) {
    reply.send(match page.document().QuerySelectorAll(DOMString::from(selector)) {
        Ok(ref nodes) => {
            let mut result = Vec::with_capacity(nodes.Length() as usize);
            for i in 0..nodes.Length() {
                if let Some(ref node) = nodes.Item(i) {
                    result.push(node.get_unique_id());
                }
            }
            Ok(result)
        },
        Err(_) => {
            Err(())
        }
    }).unwrap();
}

pub fn handle_focus_element(page: &Rc<Page>,
                            pipeline: PipelineId,
                            element_id: String,
                            reply: IpcSender<Result<(), ()>>) {
    reply.send(match find_node_by_unique_id(page, pipeline, element_id) {
        Some(ref node) => {
            match node.downcast::<HTMLElement>() {
                Some(ref elem) => {
                    // Need a way to find if this actually succeeded
                    elem.Focus();
                    Ok(())
                }
                None => Err(())
            }
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_get_active_element(page: &Rc<Page>,
                                 _pipeline: PipelineId,
                                 reply: IpcSender<Option<String>>) {
    reply.send(page.document().GetActiveElement().map(
        |elem| elem.upcast::<Node>().get_unique_id())).unwrap();
}

pub fn handle_get_title(page: &Rc<Page>, _pipeline: PipelineId, reply: IpcSender<String>) {
    reply.send(String::from(page.document().Title())).unwrap();
}

pub fn handle_get_rect(page: &Rc<Page>,
                       pipeline: PipelineId,
                       element_id: String,
                       reply: IpcSender<Result<Rect<f64>, ()>>) {
    reply.send(match find_node_by_unique_id(&*page, pipeline, element_id) {
        Some(elem) => {
            // https://w3c.github.io/webdriver/webdriver-spec.html#dfn-calculate-the-absolute-position
            match elem.downcast::<HTMLElement>() {
                Some(html_elem) => {
                    // Step 1
                    let mut x = 0;
                    let mut y = 0;

                    let mut offset_parent = html_elem.GetOffsetParent();

                    // Step 2
                    while let Some(element) = offset_parent {
                        offset_parent = match element.downcast::<HTMLElement>() {
                            Some(elem) => {
                                x += elem.OffsetLeft();
                                y += elem.OffsetTop();
                                elem.GetOffsetParent()
                            },
                            None => None
                        };
                    }
                    // Step 3
                    Ok(Rect::new(Point2D::new(x as f64, y as f64),
                                 Size2D::new(html_elem.OffsetWidth() as f64,
                                             html_elem.OffsetHeight() as f64)))
                },
                None => Err(())
            }
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_get_text(page: &Rc<Page>,
                       pipeline: PipelineId,
                       node_id: String,
                       reply: IpcSender<Result<String, ()>>) {
    reply.send(match find_node_by_unique_id(&*page, pipeline, node_id) {
        Some(ref node) => {
            Ok(node.GetTextContent().map_or("".to_owned(), String::from))
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_get_name(page: &Rc<Page>,
                       pipeline: PipelineId,
                       node_id: String,
                       reply: IpcSender<Result<String, ()>>) {
    reply.send(match find_node_by_unique_id(&*page, pipeline, node_id) {
        Some(node) => {
            Ok(String::from(node.downcast::<Element>().unwrap().TagName()))
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_get_attribute(page: &Rc<Page>,
                            pipeline: PipelineId,
                            node_id: String,
                            name: String,
                            reply: IpcSender<Result<Option<String>, ()>>) {
    reply.send(match find_node_by_unique_id(&*page, pipeline, node_id) {
        Some(node) => {
            Ok(node.downcast::<Element>().unwrap().GetAttribute(DOMString::from(name))
               .map(String::from))
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_get_css(page: &Rc<Page>,
                      pipeline: PipelineId,
                      node_id: String,
                      name: String,
                      reply: IpcSender<Result<String, ()>>) {
    reply.send(match find_node_by_unique_id(&*page, pipeline, node_id) {
        Some(node) => {
            let window = page.window();
            let elem = node.downcast::<Element>().unwrap();
            Ok(String::from(
                window.GetComputedStyle(&elem, None).GetPropertyValue(DOMString::from(name))))
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_get_url(page: &Rc<Page>,
                      _pipeline: PipelineId,
                      reply: IpcSender<Url>) {
    let document = page.document();
    let url = document.url();
    reply.send((*url).clone()).unwrap();
}

pub fn handle_get_window_size(page: &Rc<Page>,
                              _pipeline: PipelineId,
                              reply: IpcSender<Option<WindowSizeData>>) {
    let window = page.window();
    let size = window.window_size();
    reply.send(size).unwrap();
}

pub fn handle_is_enabled(page: &Rc<Page>,
                         pipeline: PipelineId,
                         element_id: String,
                         reply: IpcSender<Result<bool, ()>>) {
    reply.send(match find_node_by_unique_id(page, pipeline, element_id) {
        Some(ref node) => {
            match node.downcast::<Element>() {
                Some(elem) => Ok(elem.get_enabled_state()),
                None => Err(())
            }
        },
        None => Err(())
    }).unwrap();
}

pub fn handle_is_selected(page: &Rc<Page>,
                          pipeline: PipelineId,
                          element_id: String,
                          reply: IpcSender<Result<bool, ()>>) {
    reply.send(match find_node_by_unique_id(page, pipeline, element_id) {
        Some(ref node) => {
            if let Some(input_element) = node.downcast::<HTMLInputElement>() {
                Ok(input_element.Checked())
            }
            else if let Some(option_element) = node.downcast::<HTMLOptionElement>() {
                Ok(option_element.Selected())
            }
            else if let Some(_) = node.downcast::<HTMLElement>() {
                Ok(false) // regular elements are not selectable
            }
            else {
                Err(())
            }
        },
        None => Err(())
    }).unwrap();
}
<|endoftext|>


<commit_before>/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

use aws_config::meta::region::RegionProviderChain;
use aws_sdk_cloudwatch::{Client, Error, Region, PKG_VERSION};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    /// The AWS Region.
    #[structopt(short, long)]
    region: Option<String>,

    /// Whether to display additional information.
    #[structopt(short, long)]
    verbose: bool,
}

// List metrics.
// snippet-start:[cloudwatch.rust.list-metrics]
async fn show_metrics(
    client: &aws_sdk_cloudwatch::Client,
) -> Result<(), aws_sdk_cloudwatch::Error> {
    let rsp = client.list_metrics().send().await?;
    let metrics = rsp.metrics.unwrap_or_default();

    let num_metrics = metrics.len();

    for metric in metrics {
        println!("Namespace: {}", metric.namespace.unwrap_or_default());
        println!("Name:      {}", metric.metric_name.unwrap_or_default());
        println!("Dimensions:");

        for dimension in metric.dimensions {
            for d in dimension {
                println!("  Name:  {}", d.name.unwrap_or_default());
                println!("  Value: {}", d.value.unwrap_or_default());
                println!();
            }
        }

        println!();
    }

    println!("Found {} metrics.", num_metrics);

    Ok(())
}
// snippet-end:[cloudwatch.rust.list-metrics]

/// Lists your Amazon CloudWatch metrics in the Region.
/// # Arguments
///
/// * `[-r REGION]` - The Region in which the client is created.
///   If not supplied, uses the value of the **AWS_REGION** environment variable.
///   If the environment variable is not set, defaults to **us-west-2**.
/// * `[-v]` - Whether to display additional information.
#[tokio::main]
async fn main() -> Result<(), Error> {
    let Opt { region, verbose } = Opt::from_args();

    if verbose {
        tracing_subscriber::fmt::init();
    }

    let region_provider = RegionProviderChain::first_try(region.map(Region::new))
        .or_default_provider()
        .or_else(Region::new("us-west-2"));

    if verbose {
        println!();
        println!("CloudWatch client version: {}", PKG_VERSION);
        println!(
            "Region:                    {}",
            region_provider.region().await.unwrap().as_ref()
        );
        println!();
    }

    let shared_config = aws_config::from_env().region(region_provider).load().await;
    let client = Client::new(&shared_config);

    show_metrics(&client).await
}
<commit_msg>Updated CloudWatch code example in Rust based on feedback<commit_after>/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

use aws_config::meta::region::RegionProviderChain;
use aws_sdk_cloudwatch::{Client, Error, Region, PKG_VERSION};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    /// The AWS Region.
    #[structopt(short, long)]
    region: Option<String>,

    /// Whether to display additional information.
    #[structopt(short, long)]
    verbose: bool,
}

// List metrics.
// snippet-start:[cloudwatch.rust.list-metrics]
async fn show_metrics(
    client: &aws_sdk_cloudwatch::Client,
) -> Result<(), aws_sdk_cloudwatch::Error> {
    let rsp = client.list_metrics().send().await?;
    let metrics = rsp.metrics().unwrap_or_default();

    let num_metrics = metrics.len();

    for metric in metrics {
        println!("Namespace: {}", metric.namespace().unwrap_or_default());
        println!("Name:      {}", metric.metric_name().unwrap_or_default());
        println!("Dimensions:");

        if let Some(dimension) = metric.dimensions.as_ref() {
            for d in dimension {
                println!("  Name:  {}", d.name().unwrap_or_default());
                println!("  Value: {}", d.value().unwrap_or_default());
                println!();
            }
        }

        println!();
    }

    println!("Found {} metrics.", num_metrics);

    Ok(())
}
// snippet-end:[cloudwatch.rust.list-metrics]

/// Lists your Amazon CloudWatch metrics in the Region.
/// # Arguments
///
/// * `[-r REGION]` - The Region in which the client is created.
///   If not supplied, uses the value of the **AWS_REGION** environment variable.
///   If the environment variable is not set, defaults to **us-west-2**.
/// * `[-v]` - Whether to display additional information.
#[tokio::main]
async fn main() -> Result<(), Error> {
    let Opt { region, verbose } = Opt::from_args();

    if verbose {
        tracing_subscriber::fmt::init();
    }

    let region_provider = RegionProviderChain::first_try(region.map(Region::new))
        .or_default_provider()
        .or_else(Region::new("us-west-2"));

    if verbose {
        println!();
        println!("CloudWatch client version: {}", PKG_VERSION);
        println!(
            "Region:                    {}",
            region_provider.region().await.unwrap().as_ref()
        );
        println!();
    }

    let shared_config = aws_config::from_env().region(region_provider).load().await;
    let client = Client::new(&shared_config);

    show_metrics(&client).await
}
<|endoftext|>


<commit_before>//! Learning benchmark domains module.
use crate::geometry::Space;

macro_rules! impl_into {
    (Transition < S, $type:ty > => Transition < S,() >) => {
        impl<S> Into<Transition<S, ()>> for Transition<S, $type> {
            fn into(self) -> Transition<S, ()> { self.drop_action() }
        }
    };
}

/// Container class for data associated with a domain observation.
#[derive(Clone, Debug)]
pub enum Observation<S> {
    /// Fully observed state of the environment.
    Full(S),

    /// Partially observed state of the environment.
    Partial(S),

    /// Terminal state of the environment.
    Terminal(S),
}

impl<S> Observation<S> {
    /// Helper function returning a reference to the state values for the given
    /// observation.
    pub fn state(&self) -> &S {
        use self::Observation::*;

        match self {
            Full(ref state) | Partial(ref state) | Terminal(ref state) => state,
        }
    }

    /// Returns true if the state was fully observed, otherwise false.
    pub fn is_full(&self) -> bool {
        match self {
            Observation::Full(_) => true,
            _ => false,
        }
    }

    /// Returns true if the state was only partially observed, otherwise false.
    pub fn is_partial(&self) -> bool {
        match self {
            Observation::Partial(_) => true,
            _ => false,
        }
    }

    /// Returns true if the observation is the terminal state, otherwise false.
    pub fn is_terminal(&self) -> bool {
        match self {
            Observation::Terminal(_) => true,
            _ => false,
        }
    }
}

/// Container class for data associated with a domain transition.
#[derive(Clone, Debug)]
pub struct Transition<S, A> {
    /// State transitioned _from_, `s`.
    pub from: Observation<S>,

    /// Action taken to initiate the transition (control tasks).
    pub action: A,

    /// Reward obtained from the transition.
    pub reward: f64,

    /// State transitioned _to_, `s'`.
    pub to: Observation<S>,
}

impl<S, A> Transition<S, A> {
    /// Return references to the `from` and `to` states associated with this
    /// transition.
    pub fn states(&self) -> (&S, &S) { (self.from.state(), self.to.state()) }

    /// Apply a closure to the `from` and `to` states associated with this
    /// transition.
    pub fn map_states<O>(&self, f: impl Fn(&S) -> O) -> (O, O) {
        (f(self.from.state()), f(self.to.state()))
    }

    /// Returns true if the transition ends in a terminal state.
    pub fn terminated(&self) -> bool { self.to.is_terminal() }

    /// Replace the action associated with this transition and return a new
    /// instance.
    pub fn replace_action<T>(self, action: T) -> Transition<S, T> {
        Transition {
            from: self.from,
            action: action,
            reward: self.reward,
            to: self.to,
        }
    }

    /// Drop the action associated with this transition and return a new
    /// instance.
    pub fn drop_action(self) -> Transition<S, ()> { self.replace_action(()) }
}

impl_into!(Transition<S, u8> => Transition<S, ()>);
impl_into!(Transition<S, u16> => Transition<S, ()>);
impl_into!(Transition<S, u32> => Transition<S, ()>);
impl_into!(Transition<S, u64> => Transition<S, ()>);
impl_into!(Transition<S, usize> => Transition<S, ()>);
impl_into!(Transition<S, i8> => Transition<S, ()>);
impl_into!(Transition<S, i16> => Transition<S, ()>);
impl_into!(Transition<S, i32> => Transition<S, ()>);
impl_into!(Transition<S, i64> => Transition<S, ()>);
impl_into!(Transition<S, isize> => Transition<S, ()>);
impl_into!(Transition<S, f32> => Transition<S, ()>);
impl_into!(Transition<S, f64> => Transition<S, ()>);

/// An interface for constructing reinforcement learning problem domains.
pub trait Domain {
    /// State space representation type class.
    type StateSpace: Space;

    /// Action space representation type class.
    type ActionSpace: Space;

    /// Emit an observation of the current state of the environment.
    fn emit(&self) -> Observation<<Self::StateSpace as Space>::Value>;

    /// Transition the environment forward a single step given an action, `a`.
    fn step(
        &mut self,
        a: <Self::ActionSpace as Space>::Value,
    ) -> Transition<<Self::StateSpace as Space>::Value, <Self::ActionSpace as Space>::Value>;

    /// Returns true if the current state is terminal.
    fn is_terminal(&self) -> bool;

    /// Compute the reward associated with a transition from one state to
    /// another.
    fn reward(
        &self,
        from: &Observation<<Self::StateSpace as Space>::Value>,
        to: &Observation<<Self::StateSpace as Space>::Value>,
    ) -> f64;

    /// Returns an instance of the state space type class.
    fn state_space(&self) -> Self::StateSpace;

    /// Returns an instance of the action space type class.
    fn action_space(&self) -> Self::ActionSpace;
}

mod ode;
use self::ode::*;

mod grid_world;

import_all!(mountain_car);
import_all!(cart_pole);
import_all!(acrobat);
import_all!(hiv);
import_all!(cliff_walk);

#[cfg(feature = "openai")]
import_all!(openai);
<commit_msg>feat(domains): add Transition::negate_reward method<commit_after>//! Learning benchmark domains module.
use crate::geometry::Space;

macro_rules! impl_into {
    (Transition < S, $type:ty > => Transition < S,() >) => {
        impl<S> Into<Transition<S, ()>> for Transition<S, $type> {
            fn into(self) -> Transition<S, ()> { self.drop_action() }
        }
    };
}

/// Container class for data associated with a domain observation.
#[derive(Clone, Copy, Debug)]
pub enum Observation<S> {
    /// Fully observed state of the environment.
    Full(S),

    /// Partially observed state of the environment.
    Partial(S),

    /// Terminal state of the environment.
    Terminal(S),
}

impl<S> Observation<S> {
    /// Helper function returning a reference to the state values for the given
    /// observation.
    pub fn state(&self) -> &S {
        use self::Observation::*;

        match self {
            Full(ref state) | Partial(ref state) | Terminal(ref state) => state,
        }
    }

    /// Returns true if the state was fully observed, otherwise false.
    pub fn is_full(&self) -> bool {
        match self {
            Observation::Full(_) => true,
            _ => false,
        }
    }

    /// Returns true if the state was only partially observed, otherwise false.
    pub fn is_partial(&self) -> bool {
        match self {
            Observation::Partial(_) => true,
            _ => false,
        }
    }

    /// Returns true if the observation is the terminal state, otherwise false.
    pub fn is_terminal(&self) -> bool {
        match self {
            Observation::Terminal(_) => true,
            _ => false,
        }
    }
}

/// Container class for data associated with a domain transition.
#[derive(Clone, Copy, Debug)]
pub struct Transition<S, A> {
    /// State transitioned _from_, `s`.
    pub from: Observation<S>,

    /// Action taken to initiate the transition (control tasks).
    pub action: A,

    /// Reward obtained from the transition.
    pub reward: f64,

    /// State transitioned _to_, `s'`.
    pub to: Observation<S>,
}

impl<S, A> Transition<S, A> {
    /// Return references to the `from` and `to` states associated with this
    /// transition.
    pub fn states(&self) -> (&S, &S) { (self.from.state(), self.to.state()) }

    /// Apply a closure to the `from` and `to` states associated with this
    /// transition.
    pub fn map_states<O>(&self, f: impl Fn(&S) -> O) -> (O, O) {
        (f(self.from.state()), f(self.to.state()))
    }

    /// Returns true if the transition ends in a terminal state.
    pub fn terminated(&self) -> bool { self.to.is_terminal() }

    /// Replace the action associated with this transition and return a new
    /// instance.
    pub fn replace_action<T>(self, action: T) -> Transition<S, T> {
        Transition {
            from: self.from,
            action: action,
            reward: self.reward,
            to: self.to,
        }
    }

    /// Drop the action associated with this transition and return a new
    /// instance.
    pub fn drop_action(self) -> Transition<S, ()> { self.replace_action(()) }

    pub fn negate_reward(self) -> Transition<S, A> {
        Transition {
            from: self.from,
            action: self.action,
            reward: -self.reward,
            to: self.to,
        }
    }
}

impl_into!(Transition<S, u8> => Transition<S, ()>);
impl_into!(Transition<S, u16> => Transition<S, ()>);
impl_into!(Transition<S, u32> => Transition<S, ()>);
impl_into!(Transition<S, u64> => Transition<S, ()>);
impl_into!(Transition<S, usize> => Transition<S, ()>);
impl_into!(Transition<S, i8> => Transition<S, ()>);
impl_into!(Transition<S, i16> => Transition<S, ()>);
impl_into!(Transition<S, i32> => Transition<S, ()>);
impl_into!(Transition<S, i64> => Transition<S, ()>);
impl_into!(Transition<S, isize> => Transition<S, ()>);
impl_into!(Transition<S, f32> => Transition<S, ()>);
impl_into!(Transition<S, f64> => Transition<S, ()>);

/// An interface for constructing reinforcement learning problem domains.
pub trait Domain {
    /// State space representation type class.
    type StateSpace: Space;

    /// Action space representation type class.
    type ActionSpace: Space;

    /// Emit an observation of the current state of the environment.
    fn emit(&self) -> Observation<<Self::StateSpace as Space>::Value>;

    /// Transition the environment forward a single step given an action, `a`.
    fn step(
        &mut self,
        a: <Self::ActionSpace as Space>::Value,
    ) -> Transition<<Self::StateSpace as Space>::Value, <Self::ActionSpace as Space>::Value>;

    /// Returns true if the current state is terminal.
    fn is_terminal(&self) -> bool;

    /// Compute the reward associated with a transition from one state to
    /// another.
    fn reward(
        &self,
        from: &Observation<<Self::StateSpace as Space>::Value>,
        to: &Observation<<Self::StateSpace as Space>::Value>,
    ) -> f64;

    /// Returns an instance of the state space type class.
    fn state_space(&self) -> Self::StateSpace;

    /// Returns an instance of the action space type class.
    fn action_space(&self) -> Self::ActionSpace;
}

mod ode;
use self::ode::*;

mod grid_world;

import_all!(mountain_car);
import_all!(cart_pole);
import_all!(acrobat);
import_all!(hiv);
import_all!(cliff_walk);

#[cfg(feature = "openai")]
import_all!(openai);
<|endoftext|>


<commit_before>use std::intrinsics;

use emu::memory as mem;

mod flags;
use self::flags::Flags::*;

pub struct CPU {
	accumulator:      u16,
	index_x:          u16,
	index_y:          u16,
	stack_pointer:    u16,
	data_bank:        u16,
	direct_page:      u16,
	program_bank:     u16,
	processor_status: u16,
	program_counter:  u16,
}

impl CPU {
	pub fn new() -> CPU {
		CPU {
			accumulator:      0,
			index_x:          0,
			index_y:          0,
			stack_pointer:    0,
			data_bank:        0,
			direct_page:      0,
			program_bank:     0,
			processor_status: 0,
			program_counter:  0,
		}
	}

	pub fn execute(&self, memory: &mut mem::Memory) -> u8 {
		// opcode <- mem[self.PC]
		// cycles <- function_table[opcode]() //this will update PC
		// return cycles

		//anything else?

		1_u8
	}

	fn check_flag(&self, mask: flags::Flags) -> bool {
		match mask {
			IndexRegisterSizeFlag => {
				match self.check_flag(NativeModeFlag) {
					true  => self.processor_status & IndexRegisterSizeFlag == 1_u16,
					_     => false,
				}
			},
			AccumulatorRegisterSizeFlag => {
				match self.check_flag(NativeModeFlag) {
					true  => self.processor_status & AccumulatorRegisterSizeFlag == 1_u16,
					_     => false,
				}
			},
			ProgramBreakInterruptFlag => {
				match self.check_flag(NativeModeFlag) {
					true  => false,
					_     => self.processor_status & IndexRegisterSizeFlag == 1_u16,
				}
			},
			_ => self.processor_status & mask == 1_u16,
		}
	}

	fn set_flag(&mut self, flag: flags::Flags, do_clear: bool) {
		if do_clear {
			self.processor_status = self.processor_status ^ flag
		} else {
			self.processor_status = self.processor_status | flag
		}
	}

	// start instructions
    // TODO: Look up addressing modes for the 65816: wiki.superfamicom.org has a lot of details
    // missing

    // something's missing here
    // this instruction is a two-byte instruction
    // the opcode uses up one of the bytes, where's the other?
	fn add_with_carry_direct_page_indexed_indirect_x(&mut self, memory: &mut mem::Memory) -> u8 {
		let address    = self.direct_page + self.index_x;
        let cycles: u8 = 6
                           + (if self.check_flag(AccumulatorRegisterSizeFlag) { 0 } else { 1 }) // is this right? what if the CPU is in emulator mode?
                           + (if ((self.direct_page & 0x000F) as u8) == 0 { 0 } else { 1 });

		unsafe {
			let (result, overflow) = intrinsics::u16_add_with_overflow(memory.get_word_from_ram(address as usize), 1);

			self.set_flag(NegativeFlag, result & 0x8000 == 0x8000);
			self.set_flag(OverflowFlag, overflow);
			self.set_flag(ZeroFlag, result == 0);
			self.set_flag(CarryFlag, overflow);

			self.accumulator = result as u16;
		}

        self.program_counter += 2;

        cycles
	}

	fn add_with_carry_stack_relative(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets NVZC
	}

	fn add_with_carry_direct_page(&mut self, memory: &mut mem::Memory) -> u8 {
		3

		//Sets NVZC
	}

	fn add_with_carry_direct_page_indirect_long(&mut self, memory: &mut mem::Memory) -> u8 {
		6

		//Sets NVZC
	}

	fn add_with_carry_immediate(&mut self, memory: &mut mem::Memory) -> u8 {
		2

		//Sets NVZC
	}

	fn add_with_carry_absolute(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets NVZC
	}

	fn add_with_carry_absolute_long(&mut self, memory: &mut mem::Memory) -> u8 {
		5

		//Sets NVZC
	}

	fn add_with_carry_direct_page_indexed_indirect_y(&mut self, memory: &mut mem::Memory) -> u8 {
		let cycles: u8 = 5 + (if self.check_flag(AccumulatorRegisterSizeFlag) { 0 } else { 2 });

		//Sets NVZC

		cycles
	}

	fn add_with_carry_direct_page_indirect(&mut self, memory: &mut mem::Memory) -> u8 {
		5

		//Sets NVZC
	}

	fn add_with_carry_stack_relative_indirect_indexed_y(&mut self, memory: &mut mem::Memory) -> u8 {
		7

		//Sets NVZC
	}

	fn add_with_carry_direct_page_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets NVZC
	}

	fn add_with_carry_direct_page_indirect_long_indexed_y(&mut self, memory: &mut mem::Memory) -> u8 {
		6

		//Sets NVZC
	}

	fn add_with_carry_absolute_indexed_y(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets NVZC
	}

	fn add_with_carry_absolute_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets NVZC
	}

	fn add_with_carry_absolute_long_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		5

		//Sets NVZC
	}

	fn and_accumulator_with_memory_direct_page_indexed_indirect_x(&mut self, memory: &mut mem::Memory) -> u8 {
		6

		//Sets NZ
	}

	fn and_accumulator_with_memory_stack_relative(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets NZ
	}

	fn and_accumulator_with_memory_direct_page(&mut self, memory: &mut mem::Memory) -> u8 {
		3

		//Sets NZ
	}

	fn and_accumulator_with_memory_direct_page_indirect_long(&mut self, memory: &mut mem::Memory) -> u8 {
		6

		//Sets NZ
	}

	fn and_accumulator_with_memory_immediate(&mut self, memory: &mut mem::Memory) -> u8 {
		2

		//Sets NZ
	}

	fn and_accumulator_with_memory_absolute(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets NZ
	}

	fn and_accumulator_with_memory_absolute_long(&mut self, memory: &mut mem::Memory) -> u8 {
		5

		//Sets NZ
	}

	fn and_accumulator_with_memory_direct_page_indirect_indexed_y(&mut self, memory: &mut mem::Memory) -> u8 {
		5

		//Sets NZ
	}

	fn and_accumulator_with_memory_direct_page_indirect(&mut self, memory: &mut mem::Memory) -> u8 {
		5

		//Sets NZ
	}

	fn and_accumulator_with_memory_stack_relative_indirect_indexed_y(&mut self, memory: &mut mem::Memory) -> u8 {
		7

		//Sets NZ
	}

	fn and_accumulator_with_memory_direct_page_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets NZ
	}

	fn and_accumulator_with_memory_direct_page_indirect_long_indexed_y(&mut self, memory: &mut mem::Memory) -> u8 {
		6

		//Sets NZ
	}

	fn and_accumulator_with_memory_absolute_indexed_y(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets NZ
	}

	fn and_accumulator_with_memory_absolute_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets NZ
	}

	fn and_accumulator_with_memory_absolute_long_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		5

		//Sets NZ
	}

	fn arithmetic_shift_left_direct_page(&mut self, memory: &mut mem::Memory) -> u8 {
		let cycles = 5 + (if self.check_flag(AccumulatorRegisterSizeFlag) { 0 } else { 2 });

		//Sets NZC

		cycles
	}

	fn arithmetic_shift_left_accumulator(&mut self, memory: &mut mem::Memory) -> u8 {
		2

		//Sets NZC
	}

	fn arithmetic_shift_left_absolute(&mut self, memory: &mut mem::Memory) -> u8 {
		6

		//Sets NZC
	}

	fn arithmetic_shift_left_direct_page_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		6

		//Sets NZC
	}

	fn arithmetic_shift_left_absolute_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		7

		//Sets NZC
	}

	fn branch_if_carry_clear(&mut self) -> u8 {
		//TODO: Add 1 cycle if branch taken crosses page boundary in emulation mode
		let cycles = 2 + if !self.check_flag(CarryFlag) { 1 } else { 0 };

		cycles
	}

	fn branch_if_carry_set(&mut self) -> u8 {
		2
	}

	fn branch_if_equal(&mut self) -> u8 {
		2
	}

	fn test_bits_direct_page(&mut self, memory: &mut mem::Memory) -> u8 {
		3

		//Sets NVZ
	}

	fn test_bits_absolute(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets NVZ
	}

	fn test_bits_direct_page_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets NVZ
	}

	fn test_bits_absolute_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets NVZ
	}

	fn test_bits_immediate(&mut self, memory: &mut mem::Memory) -> u8 {
		2

		//Sets Z
	}

	fn branch_if_minus(&mut self) -> u8 {
		2
	}

	fn branch_if_not_equal(&mut self) -> u8 {
		2
	}

	fn branch_if_plus(&mut self) -> u8 {
		2
	}

	fn branch_always(&mut self) -> u8 {
		3
	}

	fn break_op(&mut self) -> u8 {
		//TODO: Add 1 cycle if in native mode
		let cycles = 7;

		//Sets DI

		cycles
	}

	fn branch_long_always(&mut self) -> u8 {
		4
	}

	fn branch_if_overflow_clear(&mut self) -> u8 {
		2
	}

	fn branch_if_overflow_set(&mut self) -> u8 {
		2
	}

	fn clear_carry(&mut self) -> u8 {
		self.set_flag(CarryFlag, false);

		2
	}

	fn clear_decimal_mode_flag(&mut self) -> u8 {
		self.set_flag(DecimalFlag, false);

		2
	}

	fn clear_interrupt_disable_flag(&mut self) -> u8 {
		self.set_flag(IRQDisableFlag, false);

		2
	}

	fn clear_overflow_flag(&mut self) -> u8 {
		self.set_flag(OverflowFlag, false);

		2
	}

	fn compare_accumulator_with_memory_direct_page_indexed_indirect_x(&mut self, memory: &mut mem::Memory) -> u8 {
		6

		//Sets: NZC
	}

	fn compare_accumulator_with_memory_stack_relative(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets: NZC
	}

	fn compare_accumulator_with_memory_direct_page(&mut self, memory: &mut mem::Memory) -> u8 {
		3

		//Sets: NZC
	}

	fn compare_accumulator_with_memory_direct_page_indirect_long(&mut self, memory: &mut mem::Memory) -> u8 {
		6

		//Sets: NZC
	}

	fn compare_accumulator_with_immediate(&mut self) -> u8 {
		2

		//Sets: NZC
	}

	fn compare_accumulator_with_memory_absolute(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets: NZC
	}

	fn compare_accumulator_with_memory_absolute_long(&mut self, memory: &mut mem::Memory) -> u8 {
		5

		//Sets: NZC
	}

	fn compare_accumulator_with_memory_direct_page_indirect_indexed_y(&mut self, memory: &mut mem::Memory) -> u8 {
		5

		//Sets: NZC
	}

	fn compare_accumulator_with_memory_direct_page_indirect(&mut self, memory: &mut mem::Memory) -> u8 {
		5

		//Sets: NZC
	}

	fn compare_accumulator_with_memory_stack_relative_indirect_indexed_y(&mut self, memory: &mut mem::Memory) -> u8 {
		7

		//Sets: NZC
	}

	fn compare_accumulator_with_memory_direct_page_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets: NZC
	}

	fn compare_accumulator_with_memory_direct_page_indirect_long_indexed_y(&mut self, memory: &mut mem::Memory) -> u8 {
		6

		//Sets: NZC
	}

	fn compare_accumulator_with_memory_absolute_indexed_y(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets: NZC
	}

	fn compare_accumulator_with_memory_absolute_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets: NZC
	}

	fn compare_accumulator_with_memory_absolute_long_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		5

		//Sets: NZC
	}

	fn coprocessor_enable(&mut self) -> u8 {
		7

		//Sets: DI
	}

	fn compare_index_register_x_with_memory_immediate(&mut self, memory: &mut mem::Memory) -> u8 {
		let cycles = 2 + (if self.check_flag(IndexRegisterSizeFlag) { 0 } else { 1 });

		//Sets: NZC

		cycles
	}

	fn compare_index_register_x_with_memory_direct_page(&mut self, memory: &mut mem::Memory) -> u8 {
		3

		//Sets: NZC
	}

	fn compare_index_register_x_with_memory_absolute(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets: NZC
	}

	fn compare_index_register_y_with_memory_immediate(&mut self, memory: &mut mem::Memory) -> u8 {
		2

		//Sets: NZC
	}

	fn compare_index_register_y_with_memory_direct_page(&mut self, memory: &mut mem::Memory) -> u8 {
		3

		//Sets: NZC
	}

	fn compare_index_register_y_with_memory_absolute(&mut self, memory: &mut mem::Memory) -> u8 {
		4

		//Sets: NZC
	}

	fn decrement_accumulator(&mut self) -> u8 {
		2

		//Sets: NZ
	}

	fn decrement_direct_page(&mut self) -> u8 {
		5

		//Sets: NZ
	}

	fn decrement_absolute(&mut self, memory: &mut mem::Memory) -> u8 {
		6

		//Sets: NZ
	}

	fn decrement_direct_page_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		6

		//Sets: NZ
	}

	fn decrement_absolute_indexed_x(&mut self, memory: &mut mem::Memory) -> u8 {
		7

		//Sets: NZ
	}

	fn decrement_index_register_x(&mut self) -> u8 {
		2

		//Sets: NZ
	}

	fn decrement_index_register_y(&mut self) -> u8 {
		2

		//Sets: NZ
	}
}
<commit_msg>Going about the instructions in the wrong way. Need to do more research into addressing modes on the 65816. Holding off until I've read through enough of 'Programming the 65816' to have an idea of what to do. Use http://github.com/pcwalton/sprocketnes as reference for how to go about things.<commit_after>use std::intrinsics;

use emu::memory as mem;

mod flags;
use self::flags::Flags::*;

pub struct CPU {
	accumulator:      u16,
	index_x:          u16,
	index_y:          u16,
	stack_pointer:    u16,
	data_bank:        u16,
	direct_page:      u16,
	program_bank:     u16,
	processor_status: u16,
	program_counter:  u16,
}

impl CPU {
	pub fn new() -> CPU {
		CPU {
			accumulator:      0,
			index_x:          0,
			index_y:          0,
			stack_pointer:    0,
			data_bank:        0,
			direct_page:      0,
			program_bank:     0,
			processor_status: 0,
			program_counter:  0,
		}
	}

	pub fn execute(&self, memory: &mut mem::Memory) -> u8 {
		// opcode <- mem[self.PC]
		// cycles <- instruction_table[opcode]() //this will update PC
		// return cycles

		//anything else?

		1_u8
	}

	fn check_flag(&self, mask: flags::Flags) -> bool {
		match mask {
			IndexRegisterSizeFlag => {
				match self.check_flag(NativeModeFlag) {
					true  => self.processor_status & IndexRegisterSizeFlag == 1_u16,
					_     => false,
				}
			},
			AccumulatorRegisterSizeFlag => {
				match self.check_flag(NativeModeFlag) {
					true  => self.processor_status & AccumulatorRegisterSizeFlag == 1_u16,
					_     => false,
				}
			},
			ProgramBreakInterruptFlag => {
				match self.check_flag(NativeModeFlag) {
					true  => false,
					_     => self.processor_status & IndexRegisterSizeFlag == 1_u16,
				}
			},
			_ => self.processor_status & mask == 1_u16,
		}
	}

	fn set_flag(&mut self, flag: flags::Flags, do_clear: bool) {
		if do_clear {
			self.processor_status = self.processor_status ^ flag
		} else {
			self.processor_status = self.processor_status | flag
		}
	}

	// start instructions
	//TODO: Read "Programming the 65816"
}
<|endoftext|>


<commit_before>use gfx;
use gfx_phase;

mod pipe;

pub use self::pipe::{order, Pipeline};

pub type Phase<R, E> = gfx_phase::CachedPhase<R,
    ::Material<R>,
    ::view::Info<f32>,
    Technique<R>,
    E,
>;

#[derive(Clone)]
#[shader_param]
pub struct Params<R: gfx::Resources> {
    #[name = "u_Transform"]
    pub mvp: [[f32; 4]; 4],
    #[name = "u_NormalRotation"]
    pub normal: [[f32; 3]; 3],
    #[name = "u_Color"]
    pub color: [f32; 4],
    #[name = "t_Diffuse"]
    pub texture: gfx::shade::TextureParam<R>,
}

const PHONG_VS    : &'static [u8] = include_bytes!("../../gpu/phong.glslv");
const PHONG_FS    : &'static [u8] = include_bytes!("../../gpu/phong.glslf");
const PHONG_TEX_VS: &'static [u8] = include_bytes!("../../gpu/phong_tex.glslv");
const PHONG_TEX_FS: &'static [u8] = include_bytes!("../../gpu/phong_tex.glslf");

pub enum Error {
    Texture(gfx::tex::TextureError),
    Program(gfx::ProgramError),
}

impl From<gfx::tex::TextureError> for Error {
    fn from(e: gfx::tex::TextureError) -> Error {
        Error::Texture(e)
    }
}

impl From<gfx::ProgramError> for Error {
    fn from(e: gfx::ProgramError) -> Error {
        Error::Program(e)
    }
}

pub struct Technique<R: gfx::Resources> {
    program: gfx::ProgramHandle<R>,
    program_textured: gfx::ProgramHandle<R>,
    state_add: gfx::DrawState,
    state_alpha: gfx::DrawState,
    state_opaque: gfx::DrawState,
    state_multiply: gfx::DrawState,
    pub default_texture: gfx::TextureHandle<R>,
}

impl<R: gfx::Resources> Technique<R> {
    pub fn new<F: gfx::Factory<R>>(factory: &mut F)
               -> Result<Technique<R>, Error> {
        use gfx::traits::FactoryExt;
        let texture = try!(factory.create_texture_rgba8_static(1, 1, &[0xFFFFFFFF]));
        let prog0 = try!(factory.link_program(PHONG_VS, PHONG_FS));
        let prog1 = try!(factory.link_program(PHONG_TEX_VS, PHONG_TEX_FS));
        let state = gfx::DrawState::new().depth(
            gfx::state::Comparison::LessEqual,
            true
        );
        Ok(Technique {
            program: prog0,
            program_textured: prog1,
            state_add: state.clone().blend(gfx::BlendPreset::Add),
            state_alpha: state.clone().blend(gfx::BlendPreset::Alpha),
            state_multiply: state.clone().blend(gfx::BlendPreset::Multiply),
            state_opaque: state,
            default_texture: texture,
        })
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Kernel {
    textured: bool,
    blend: Option<gfx::BlendPreset>,
}

impl<R: gfx::Resources> gfx_phase::Technique<R, ::Material<R>, ::view::Info<f32>> for Technique<R> {
    type Kernel = Kernel;
    type Params = Params<R>;

    fn test(&self, mesh: &gfx::Mesh<R>, mat: &::Material<R>) -> Option<Kernel> {
        if !mat.visible {
            return None
        }
        Some(Kernel {
            textured: mat.texture.is_some() &&
                mesh.attributes.iter().find(|a| a.name == "a_Tex0").is_some(),
            blend: match mat.blend {
               Some(gfx::BlendPreset::Invert) => return None,
               other => other,
            },
        })
    }

    fn compile<'a>(&'a self, kernel: Kernel, _space: ::view::Info<f32>)
                   -> gfx_phase::TechResult<'a, R, Params<R>> {
        (   if kernel.textured {
                &self.program_textured
            } else {
                &self.program
            },
            Params {
                mvp: [[0.0; 4]; 4],
                normal: [[0.0; 3]; 3],
                color: [0.0; 4],
                texture: (self.default_texture.clone(), None),
            },
            None,
            match kernel.blend {
                Some(gfx::BlendPreset::Add) => &self.state_add,
                Some(gfx::BlendPreset::Alpha) => &self.state_alpha,
                Some(gfx::BlendPreset::Multiply) => &self.state_multiply,
                _ => &self.state_opaque,
            }
        )
    }

    fn fix_params(&self, mat: &::Material<R>, space: &::view::Info<f32>, params: &mut Params<R>) {
        use cgmath::FixedArray;
        params.mvp = *space.mx_vertex.as_fixed();
        params.normal = *space.mx_normal.as_fixed();
        params.color = mat.color;
        if let Some(ref tex) = mat.texture {
            params.texture = tex.clone();
        }
    }
}
<commit_msg>Deriving more for the Error<commit_after>use gfx;
use gfx_phase;

mod pipe;

pub use self::pipe::{order, Pipeline};

pub type Phase<R, E> = gfx_phase::CachedPhase<R,
    ::Material<R>,
    ::view::Info<f32>,
    Technique<R>,
    E,
>;

#[derive(Clone)]
#[shader_param]
pub struct Params<R: gfx::Resources> {
    #[name = "u_Transform"]
    pub mvp: [[f32; 4]; 4],
    #[name = "u_NormalRotation"]
    pub normal: [[f32; 3]; 3],
    #[name = "u_Color"]
    pub color: [f32; 4],
    #[name = "t_Diffuse"]
    pub texture: gfx::shade::TextureParam<R>,
}

const PHONG_VS    : &'static [u8] = include_bytes!("../../gpu/phong.glslv");
const PHONG_FS    : &'static [u8] = include_bytes!("../../gpu/phong.glslf");
const PHONG_TEX_VS: &'static [u8] = include_bytes!("../../gpu/phong_tex.glslv");
const PHONG_TEX_FS: &'static [u8] = include_bytes!("../../gpu/phong_tex.glslf");

#[derive(Clone, Debug, PartialEq)]
pub enum Error {
    Texture(gfx::tex::TextureError),
    Program(gfx::ProgramError),
}

impl From<gfx::tex::TextureError> for Error {
    fn from(e: gfx::tex::TextureError) -> Error {
        Error::Texture(e)
    }
}

impl From<gfx::ProgramError> for Error {
    fn from(e: gfx::ProgramError) -> Error {
        Error::Program(e)
    }
}

pub struct Technique<R: gfx::Resources> {
    program: gfx::ProgramHandle<R>,
    program_textured: gfx::ProgramHandle<R>,
    state_add: gfx::DrawState,
    state_alpha: gfx::DrawState,
    state_opaque: gfx::DrawState,
    state_multiply: gfx::DrawState,
    pub default_texture: gfx::TextureHandle<R>,
}

impl<R: gfx::Resources> Technique<R> {
    pub fn new<F: gfx::Factory<R>>(factory: &mut F)
               -> Result<Technique<R>, Error> {
        use gfx::traits::FactoryExt;
        let texture = try!(factory.create_texture_rgba8_static(1, 1, &[0xFFFFFFFF]));
        let prog0 = try!(factory.link_program(PHONG_VS, PHONG_FS));
        let prog1 = try!(factory.link_program(PHONG_TEX_VS, PHONG_TEX_FS));
        let state = gfx::DrawState::new().depth(
            gfx::state::Comparison::LessEqual,
            true
        );
        Ok(Technique {
            program: prog0,
            program_textured: prog1,
            state_add: state.clone().blend(gfx::BlendPreset::Add),
            state_alpha: state.clone().blend(gfx::BlendPreset::Alpha),
            state_multiply: state.clone().blend(gfx::BlendPreset::Multiply),
            state_opaque: state,
            default_texture: texture,
        })
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Kernel {
    textured: bool,
    blend: Option<gfx::BlendPreset>,
}

impl<R: gfx::Resources> gfx_phase::Technique<R, ::Material<R>, ::view::Info<f32>> for Technique<R> {
    type Kernel = Kernel;
    type Params = Params<R>;

    fn test(&self, mesh: &gfx::Mesh<R>, mat: &::Material<R>) -> Option<Kernel> {
        if !mat.visible {
            return None
        }
        Some(Kernel {
            textured: mat.texture.is_some() &&
                mesh.attributes.iter().find(|a| a.name == "a_Tex0").is_some(),
            blend: match mat.blend {
               Some(gfx::BlendPreset::Invert) => return None,
               other => other,
            },
        })
    }

    fn compile<'a>(&'a self, kernel: Kernel, _space: ::view::Info<f32>)
                   -> gfx_phase::TechResult<'a, R, Params<R>> {
        (   if kernel.textured {
                &self.program_textured
            } else {
                &self.program
            },
            Params {
                mvp: [[0.0; 4]; 4],
                normal: [[0.0; 3]; 3],
                color: [0.0; 4],
                texture: (self.default_texture.clone(), None),
            },
            None,
            match kernel.blend {
                Some(gfx::BlendPreset::Add) => &self.state_add,
                Some(gfx::BlendPreset::Alpha) => &self.state_alpha,
                Some(gfx::BlendPreset::Multiply) => &self.state_multiply,
                _ => &self.state_opaque,
            }
        )
    }

    fn fix_params(&self, mat: &::Material<R>, space: &::view::Info<f32>, params: &mut Params<R>) {
        use cgmath::FixedArray;
        params.mvp = *space.mx_vertex.as_fixed();
        params.normal = *space.mx_normal.as_fixed();
        params.color = mat.color;
        if let Some(ref tex) = mat.texture {
            params.texture = tex.clone();
        }
    }
}
<|endoftext|>


<commit_before>//! The lexer: split the source into a stream of tokens

use std::borrow::ToOwned;
use std::str::CharIndices;
use ast::{BinOp, UnOp, Spanned};
use driver::session;
use driver::codemap::Loc;
use front::tokens::{Token, lookup_keyword};

pub struct Lexer<'a> {
    source: &'a str,
    len: usize,

    iter: CharIndices<'a>,
    pos: usize,
    curr: Option<char>,

    lineno: usize
}

impl<'a> Lexer<'a> {
    // --- Lexer: The public API ------------------------------------------------

    /// Create a new lexer from a given string and file name
    pub fn new(source: &'a str, _: &'a str) -> Lexer<'a> {
        let mut iter = source.char_indices();
        let (pos, curr) = iter.next().unwrap();

        Lexer {
            source: source,
            len: source.len(),

            pos: pos,
            curr: Some(curr),

            iter: iter,

            lineno: 1
        }
    }

    /// Get the next token
    pub fn next_token(&mut self) -> Spanned<Token> {
        while !self.is_eof() {
            // Read the next token as long as the lexer requests us to do so
            if let Some(token) = self.read_token() {
                return token;
            }
        }

        Spanned::new(Token::EOF, self.pos as u32, self.pos as u32)
    }

    /// Tokenize the string into a vector. Used for testing
    /*
    // FIXME: Can this be removed?
    pub fn tokenize(&mut self) -> Vec<Spanned<Token>> {
        let mut tokens = vec![];

        while !self.is_eof() {
            debug!("Processing {:?}", self.curr);

            if let Some(t) = self.read_token() {
                tokens.push(t);
            }

            debug!("So far: {:?}", tokens)
        }

        tokens
    }
    */

    // --- Lexer: Helpers -------------------------------------------------------

    /// Report a fatal error back to the user
    fn fatal(&self, msg: String) -> ! {
        fatal_at!(msg; self.get_source());
        session().abort()
    }

    /// Are we done yet?
    fn is_eof(&self) -> bool {
        self.curr.is_none()
    }

    /// Get the current source position we're at
    pub fn get_source(&self) -> Loc {
        session().codemap.resolve(self.pos as u32)
    }

    // --- Lexer: Character processing ------------------------------------------

    /// Move along to the next character
    fn bump(&mut self) {
        if let Some((pos, curr)) = self.iter.next() {
            self.curr = Some(curr);
            self.pos = pos;
        } else {
            self.curr = None;
            self.pos = self.source.len();
        }

        debug!("Moved on to {:?}", self.curr)
    }

    /// An escaped representation of the current character
    fn curr_escaped(&self) -> String {
        match self.curr {
            Some(c) => c.escape_default().collect(),
            None    => "EOF".to_owned()
        }
    }

    /// Consume an expected character or report an error
    fn expect(&mut self, expect: char) {
        if self.curr != Some(expect) {
            // Build error message
            let found_str = match self.curr {
                Some(_) => format!("`{}`", self.curr_escaped()),
                None    => String::from_str("EOF")
            };

            self.fatal(format!("Expected `{}`, found {}",
                               expect, found_str))
        }

        // Consume the current character
        self.bump();
    }

    /// Collect & consume all consecutive characters into a string as long as a condition is true
    fn collect<F>(&mut self, cond: F) -> &'a str
            where F: Fn(&char) -> bool
    {
        let start = self.pos;

        debug!("start colleting (start = {}, char = {:?})", start, self.curr);

        while let Some(c) = self.curr {
            if cond(&c) {
                self.bump();
            } else {
                break;
            }
        }

        debug!("colleting finished (pos = {})", self.pos);

        &self.source[start..self.pos]
    }

    /// Consume all consecutive characters matching a condition
    fn eat_all<F>(&mut self, cond: F)
            where F: Fn(&char) -> bool {
        while let Some(c) = self.curr {
            if cond(&c) { self.bump(); }
            else { break; }
        }
    }

    // --- Lexer: Tokenizers ----------------------------------------------------

    /// Skip over a comment string
    fn skip_comment(&mut self) {
        self.eat_all(|c| *c != '\n');
    }

    /// Tokenize an identifier
    fn tokenize_ident(&mut self) -> Token {
        debug!("tokenizing an ident");

        let ident = self.collect(|c| {
            c.is_alphabetic() || c.is_numeric() || *c == '_'
        });

        // Check whether it's a keyword or an identifier
        if let Some(kw) = lookup_keyword(&ident) {
            Token::Keyword(kw)
        } else {
            Token::Ident(session().interner.intern(ident))
        }
    }

    /// Tokenize an integer
    fn tokenize_integer(&mut self) -> Token {
        debug!("tokenizing a digit");

        let integer_str = self.collect(|c| c.is_numeric());
        let integer     = match integer_str.parse() {
            Ok(i) => i,
            Err(_) => self.fatal(format!("invalid integer: `{}`", integer_str))
        };

        Token::Int(integer)
    }

    /// Tokenize a character. Correctly handles escaped newlines and escaped single quotes
    fn tokenize_char(&mut self) -> Token {
        debug!("tokenizing a char");

        self.bump();  // '\'' matched, move on

        let c = self.curr.unwrap_or_else(|| {
            self.fatal(format!("expected a char, found EOF"));
        });
        let tok = if c == '\\' {
            // Escaped char, let's take a look on one more char
            self.bump();
            match self.curr {
                Some('n')  => Token::Char('\n'),
                Some('\'') => Token::Char('\''),
                Some(c) => self.fatal(format!("unsupported or invalid escape sequence: \\{}", c)),
                None => self.fatal(format!("expected escaped char, found EOF"))
            }
        } else {
            Token::Char(c)
        };
        self.bump();  // Matched a (possibly escaped) character, move along

        // Match closing quote
        self.expect('\'');

        tok
    }

    /// Read the next token and return it
    ///
    /// If `None` is returned, the current token is to be ignored and the
    /// lexer requests the reader to read the next token instead.
    ///
    /// Precondition: self.curr is not None
    fn read_token(&mut self) -> Option<Spanned<Token>> {
        macro_rules! emit(
            ($_self:ident, $( next: $ch:expr => $tok:expr ),* ; default: $default:expr) => (
                {
                    $_self.bump();
                    match $_self.curr {
                        $( Some($ch) => { $_self.bump(); $tok } , )*
                        _ => $default
                    }
                }
            );

            ($_self:ident, $token:expr) => (
                {
                    $_self.bump();
                    $token
                }
            );
        );

        debug!("tokenizing with current character = `{}` at {}",
                 self.curr_escaped(), self.pos);

        let c = self.curr.unwrap();
        let lo = self.pos;

        let token: Token = match c {
            '+' => emit!(self, Token::BinOp(BinOp::Add)),

            '-' => emit!(self, next: '>' => Token::RArrow;
                               default: Token::BinOp(BinOp::Sub)),

            '*' => emit!(self, next: '*' => Token::BinOp(BinOp::Pow);
                               default: Token::BinOp(BinOp::Mul)),

            '/' => emit!(self, next: '/' => { self.skip_comment(); return None };
                               default: Token::BinOp(BinOp::Div)),

            '%' => emit!(self, Token::BinOp(BinOp::Mod)),

            '&' => emit!(self, next: '&' => Token::BinOp(BinOp::And);
                               default: Token::BinOp(BinOp::BitAnd)),

            '|' => emit!(self, next: '|' => Token::BinOp(BinOp::Or);
                               default: Token::BinOp(BinOp::BitOr)),

            '^' => emit!(self, Token::BinOp(BinOp::BitXor)),

            '<' => emit!(self, next: '<' => Token::BinOp(BinOp::Shl),
                               next: '=' => Token::BinOp(BinOp::Le);
                               default: Token::BinOp(BinOp::Lt)),

            '>' => emit!(self, next: '>' => Token::BinOp(BinOp::Shr),
                               next: '=' => Token::BinOp(BinOp::Ge);
                               default: Token::BinOp(BinOp::Gt)),

            '=' => emit!(self, next: '=' => Token::BinOp(BinOp::EqEq);
                               default: Token::Eq),

            '!' => emit!(self, next: '=' => Token::BinOp(BinOp::Ne);
                               default: Token::UnOp(UnOp::Not)),

            '(' => emit!(self, Token::LParen),

            ')' => emit!(self, Token::RParen),

            '{' => emit!(self, Token::LBrace),

            '}' => emit!(self, Token::RBrace),

            ',' => emit!(self, Token::Comma),

            ':' => emit!(self, Token::Colon),

            ';' => emit!(self, Token::Semicolon),

            '\'' => self.tokenize_char(),

            c if c.is_alphabetic()  => self.tokenize_ident(),

            c if c.is_numeric() => self.tokenize_integer(),

            c if c.is_whitespace() => {
                // Skip whitespaces of any type
                if c == '\n' {
                    self.lineno += 1;
                    //let offset = if self.nextch() == Some('\r') { 2 } else { 1 };
                    session().codemap.new_line(self.pos as u32 + 1)
                }

                self.bump();
                return None;
            },
            c => self.fatal(format!("unexpected character: `{}`", c))
        };

        debug!("emitted token: `{:?}`", token);

        Some(Spanned::new(token, lo as u32, self.pos as u32))
    }
}<commit_msg>Fix dead code warning<commit_after>//! The lexer: split the source into a stream of tokens

use std::borrow::ToOwned;
use std::str::CharIndices;
use ast::{BinOp, UnOp, Spanned};
use driver::session;
use driver::codemap::Loc;
use front::tokens::{Token, lookup_keyword};

pub struct Lexer<'a> {
    source: &'a str,

    iter: CharIndices<'a>,
    pos: usize,
    curr: Option<char>,

    lineno: usize
}

impl<'a> Lexer<'a> {
    // --- Lexer: The public API ------------------------------------------------

    /// Create a new lexer from a given string and file name
    pub fn new(source: &'a str, _: &'a str) -> Lexer<'a> {
        let mut iter = source.char_indices();
        let (pos, curr) = iter.next().unwrap();

        Lexer {
            source: source,

            pos: pos,
            curr: Some(curr),

            iter: iter,

            lineno: 1
        }
    }

    /// Get the next token
    pub fn next_token(&mut self) -> Spanned<Token> {
        while !self.is_eof() {
            // Read the next token as long as the lexer requests us to do so
            if let Some(token) = self.read_token() {
                return token;
            }
        }

        Spanned::new(Token::EOF, self.pos as u32, self.pos as u32)
    }

    /// Tokenize the string into a vector. Used for testing
    /*
    // FIXME: Can this be removed?
    pub fn tokenize(&mut self) -> Vec<Spanned<Token>> {
        let mut tokens = vec![];

        while !self.is_eof() {
            debug!("Processing {:?}", self.curr);

            if let Some(t) = self.read_token() {
                tokens.push(t);
            }

            debug!("So far: {:?}", tokens)
        }

        tokens
    }
    */

    // --- Lexer: Helpers -------------------------------------------------------

    /// Report a fatal error back to the user
    fn fatal(&self, msg: String) -> ! {
        fatal_at!(msg; self.get_source());
        session().abort()
    }

    /// Are we done yet?
    fn is_eof(&self) -> bool {
        self.curr.is_none()
    }

    /// Get the current source position we're at
    pub fn get_source(&self) -> Loc {
        session().codemap.resolve(self.pos as u32)
    }

    // --- Lexer: Character processing ------------------------------------------

    /// Move along to the next character
    fn bump(&mut self) {
        if let Some((pos, curr)) = self.iter.next() {
            self.curr = Some(curr);
            self.pos = pos;
        } else {
            self.curr = None;
            self.pos = self.source.len();
        }

        debug!("Moved on to {:?}", self.curr)
    }

    /// An escaped representation of the current character
    fn curr_escaped(&self) -> String {
        match self.curr {
            Some(c) => c.escape_default().collect(),
            None    => "EOF".to_owned()
        }
    }

    /// Consume an expected character or report an error
    fn expect(&mut self, expect: char) {
        if self.curr != Some(expect) {
            // Build error message
            let found_str = match self.curr {
                Some(_) => format!("`{}`", self.curr_escaped()),
                None    => String::from_str("EOF")
            };

            self.fatal(format!("Expected `{}`, found {}",
                               expect, found_str))
        }

        // Consume the current character
        self.bump();
    }

    /// Collect & consume all consecutive characters into a string as long as a condition is true
    fn collect<F>(&mut self, cond: F) -> &'a str
            where F: Fn(&char) -> bool
    {
        let start = self.pos;

        debug!("start colleting (start = {}, char = {:?})", start, self.curr);

        while let Some(c) = self.curr {
            if cond(&c) {
                self.bump();
            } else {
                break;
            }
        }

        debug!("colleting finished (pos = {})", self.pos);

        &self.source[start..self.pos]
    }

    /// Consume all consecutive characters matching a condition
    fn eat_all<F>(&mut self, cond: F)
            where F: Fn(&char) -> bool {
        while let Some(c) = self.curr {
            if cond(&c) { self.bump(); }
            else { break; }
        }
    }

    // --- Lexer: Tokenizers ----------------------------------------------------

    /// Skip over a comment string
    fn skip_comment(&mut self) {
        self.eat_all(|c| *c != '\n');
    }

    /// Tokenize an identifier
    fn tokenize_ident(&mut self) -> Token {
        debug!("tokenizing an ident");

        let ident = self.collect(|c| {
            c.is_alphabetic() || c.is_numeric() || *c == '_'
        });

        // Check whether it's a keyword or an identifier
        if let Some(kw) = lookup_keyword(&ident) {
            Token::Keyword(kw)
        } else {
            Token::Ident(session().interner.intern(ident))
        }
    }

    /// Tokenize an integer
    fn tokenize_integer(&mut self) -> Token {
        debug!("tokenizing a digit");

        let integer_str = self.collect(|c| c.is_numeric());
        let integer     = match integer_str.parse() {
            Ok(i) => i,
            Err(_) => self.fatal(format!("invalid integer: `{}`", integer_str))
        };

        Token::Int(integer)
    }

    /// Tokenize a character. Correctly handles escaped newlines and escaped single quotes
    fn tokenize_char(&mut self) -> Token {
        debug!("tokenizing a char");

        self.bump();  // '\'' matched, move on

        let c = self.curr.unwrap_or_else(|| {
            self.fatal(format!("expected a char, found EOF"));
        });
        let tok = if c == '\\' {
            // Escaped char, let's take a look on one more char
            self.bump();
            match self.curr {
                Some('n')  => Token::Char('\n'),
                Some('\'') => Token::Char('\''),
                Some(c) => self.fatal(format!("unsupported or invalid escape sequence: \\{}", c)),
                None => self.fatal(format!("expected escaped char, found EOF"))
            }
        } else {
            Token::Char(c)
        };
        self.bump();  // Matched a (possibly escaped) character, move along

        // Match closing quote
        self.expect('\'');

        tok
    }

    /// Read the next token and return it
    ///
    /// If `None` is returned, the current token is to be ignored and the
    /// lexer requests the reader to read the next token instead.
    ///
    /// Precondition: self.curr is not None
    fn read_token(&mut self) -> Option<Spanned<Token>> {
        macro_rules! emit(
            ($_self:ident, $( next: $ch:expr => $tok:expr ),* ; default: $default:expr) => (
                {
                    $_self.bump();
                    match $_self.curr {
                        $( Some($ch) => { $_self.bump(); $tok } , )*
                        _ => $default
                    }
                }
            );

            ($_self:ident, $token:expr) => (
                {
                    $_self.bump();
                    $token
                }
            );
        );

        debug!("tokenizing with current character = `{}` at {}",
                 self.curr_escaped(), self.pos);

        let c = self.curr.unwrap();
        let lo = self.pos;

        let token: Token = match c {
            '+' => emit!(self, Token::BinOp(BinOp::Add)),

            '-' => emit!(self, next: '>' => Token::RArrow;
                               default: Token::BinOp(BinOp::Sub)),

            '*' => emit!(self, next: '*' => Token::BinOp(BinOp::Pow);
                               default: Token::BinOp(BinOp::Mul)),

            '/' => emit!(self, next: '/' => { self.skip_comment(); return None };
                               default: Token::BinOp(BinOp::Div)),

            '%' => emit!(self, Token::BinOp(BinOp::Mod)),

            '&' => emit!(self, next: '&' => Token::BinOp(BinOp::And);
                               default: Token::BinOp(BinOp::BitAnd)),

            '|' => emit!(self, next: '|' => Token::BinOp(BinOp::Or);
                               default: Token::BinOp(BinOp::BitOr)),

            '^' => emit!(self, Token::BinOp(BinOp::BitXor)),

            '<' => emit!(self, next: '<' => Token::BinOp(BinOp::Shl),
                               next: '=' => Token::BinOp(BinOp::Le);
                               default: Token::BinOp(BinOp::Lt)),

            '>' => emit!(self, next: '>' => Token::BinOp(BinOp::Shr),
                               next: '=' => Token::BinOp(BinOp::Ge);
                               default: Token::BinOp(BinOp::Gt)),

            '=' => emit!(self, next: '=' => Token::BinOp(BinOp::EqEq);
                               default: Token::Eq),

            '!' => emit!(self, next: '=' => Token::BinOp(BinOp::Ne);
                               default: Token::UnOp(UnOp::Not)),

            '(' => emit!(self, Token::LParen),

            ')' => emit!(self, Token::RParen),

            '{' => emit!(self, Token::LBrace),

            '}' => emit!(self, Token::RBrace),

            ',' => emit!(self, Token::Comma),

            ':' => emit!(self, Token::Colon),

            ';' => emit!(self, Token::Semicolon),

            '\'' => self.tokenize_char(),

            c if c.is_alphabetic()  => self.tokenize_ident(),

            c if c.is_numeric() => self.tokenize_integer(),

            c if c.is_whitespace() => {
                // Skip whitespaces of any type
                if c == '\n' {
                    self.lineno += 1;
                    //let offset = if self.nextch() == Some('\r') { 2 } else { 1 };
                    session().codemap.new_line(self.pos as u32 + 1)
                }

                self.bump();
                return None;
            },
            c => self.fatal(format!("unexpected character: `{}`", c))
        };

        debug!("emitted token: `{:?}`", token);

        Some(Spanned::new(token, lo as u32, self.pos as u32))
    }
}<|endoftext|>