<commit_before>// Copyright 2020 Google LLC
//
// 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 crate::bundle::{Bundle, Exchange, Request, Response, Uri, Version};
use crate::prelude::*;
use headers::{ContentLength, ContentType, HeaderMapExt as _};
use http::StatusCode;
use std::path::{Path, PathBuf};
use url::Url;
use walkdir::WalkDir;

#[derive(Default)]
pub struct Builder {
    version: Option<Version>,
    primary_url: Option<Uri>,
    manifest: Option<Uri>,
    exchanges: Vec<Exchange>,
}

impl Builder {
    pub(crate) fn new() -> Self {
        Default::default()
    }

    /// Sets the version.
    pub fn version(mut self, version: Version) -> Self {
        self.version = Some(version);
        self
    }

    /// Sets the primary url.
    pub fn primary_url(mut self, primary_url: Uri) -> Self {
        self.primary_url = Some(primary_url);
        self
    }

    /// Sets the manifest url.
    pub fn manifest(mut self, manifest: Uri) -> Self {
        self.manifest = Some(manifest);
        self
    }

    /// Adds the exchange.
    pub fn exchange(mut self, exchange: Exchange) -> Self {
        self.exchanges.push(exchange);
        self
    }

    /// Append exchanges from the files under the given directory.
    ///
    /// `base_url` will be used as a prefix for each
    /// resource. A relative path from the given directory to each
    /// file is appended to `base_url`.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use webbundle::{Bundle, Version};
    /// let bundle = Bundle::builder()
    ///        .version(Version::VersionB1)
    ///        .primary_url("https://example.com/index.html".parse()?)
    ///        .exchanges_from_dir("assets", "https://example.com".parse()?)?
    ///        .build()?;
    /// # Result::Ok::<(), anyhow::Error>(())
    /// ```
    pub fn exchanges_from_dir(mut self, dir: impl AsRef<Path>, base_url: Url) -> Result<Self> {
        self.exchanges.append(
            &mut ExchangeBuilder::new(PathBuf::from(dir.as_ref()), base_url)
                .walk()?
                .build(),
        );
        Ok(self)
    }

    /// Builds the bundle.
    pub fn build(self) -> Result<Bundle> {
        Ok(Bundle {
            version: self.version.context("no version")?,
            primary_url: self.primary_url.context("no primary_url")?,
            manifest: self.manifest,
            exchanges: self.exchanges,
        })
    }
}

#[allow(dead_code)]
struct ExchangeBuilder {
    base_url: Url,
    base_dir: PathBuf,
    exchanges: Vec<Exchange>,
}

#[allow(dead_code)]
impl ExchangeBuilder {
    fn new(base_dir: PathBuf, base_url: Url) -> Self {
        ExchangeBuilder {
            base_dir,
            base_url,
            exchanges: Vec::new(),
        }
    }

    fn walk(mut self) -> Result<Self> {
        for entry in WalkDir::new(&self.base_dir) {
            let entry = entry?;
            let file_type = entry.file_type();
            if file_type.is_symlink() {
                log::warn!(
                    "path is symbolink link. Skipping. {}",
                    entry.path().display()
                );
                continue;
            }
            if file_type.is_file() {
                let relative_path = pathdiff::diff_paths(entry.path(), &self.base_dir).unwrap();
                self = self.exchange(relative_path)?;
            }
        }
        Ok(self)
    }

    fn build(self) -> Vec<Exchange> {
        self.exchanges
    }

    fn url_from_relative_path(&self, relative_path: &Path) -> Result<Uri> {
        ensure!(
            relative_path.is_relative(),
            format!("Path is not relative: {}", relative_path.display())
        );
        Ok(self
            .base_url
            .join(&relative_path.display().to_string())?
            .to_string()
            .parse()?)
    }

    fn exchange(mut self, relative_path: impl AsRef<Path>) -> Result<Self> {
        self.exchanges.push(Exchange {
            request: Request::get(self.url_from_relative_path(relative_path.as_ref())?).body(())?,
            response: self.create_response(relative_path)?,
        });
        Ok(self)
    }

    fn create_response(&self, relative_path: impl AsRef<Path>) -> Result<Response> {
        ensure!(
            relative_path.as_ref().is_relative(),
            format!("Path is not relative: {}", relative_path.as_ref().display())
        );
        let path = self.base_dir.join(relative_path);
        let body = std::fs::read(&path)?;

        let content_length = ContentLength(body.len() as u64);
        let content_type = ContentType::from(mime_guess::from_path(&path).first_or_octet_stream());

        let mut response = Response::new(body);
        *response.status_mut() = StatusCode::OK;
        response.headers_mut().typed_insert(content_length);
        response.headers_mut().typed_insert(content_type);
        Ok(response)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashSet;

    #[test]
    fn build_fail() {
        assert!(Builder::new().build().is_err());
    }

    #[test]
    fn build() -> Result<()> {
        let bundle = Builder::new()
            .version(Version::Version1)
            .primary_url("https://example.com".parse()?)
            .build()?;
        assert_eq!(bundle.version, Version::Version1);
        assert_eq!(bundle.primary_url, "https://example.com".parse::<Uri>()?);
        Ok(())
    }

    #[test]
    fn exchange_builder() -> Result<()> {
        let base_dir = {
            let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
            path.push("tests/builder");
            path
        };

        let exchanges = ExchangeBuilder::new(base_dir.clone(), "https://example.com/".parse()?)
            .exchange("index.html")?
            .build();
        assert_eq!(exchanges.len(), 1);
        let exchange = &exchanges[0];
        assert_eq!(
            exchange.request.uri(),
            &"https://example.com/index.html".parse::<Uri>()?
        );
        assert_eq!(exchange.response.status(), StatusCode::OK);
        assert_eq!(exchange.response.headers()["content-type"], "text/html");
        assert_eq!(
            exchange.response.headers()["content-length"],
            std::fs::read(base_dir.join("index.html"))?
                .len()
                .to_string()
        );
        assert_eq!(
            exchange.response.body(),
            &std::fs::read(base_dir.join("index.html"))?
        );
        Ok(())
    }

    #[test]
    fn walk() -> Result<()> {
        let base_dir = {
            let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
            path.push("tests/builder");
            path
        };

        let exchanges = ExchangeBuilder::new(base_dir, "https://example.com/".parse()?)
            .walk()?
            .build();
        assert_eq!(exchanges.len(), 2);
        let urls = exchanges
            .into_iter()
            .map(|e| e.request.uri().to_string())
            .collect::<HashSet<_>>();
        assert!(urls.contains("https://example.com/index.html"));
        assert!(urls.contains("https://example.com/js/hello.js"));
        Ok(())
    }
}
<commit_msg>Serve index.html file from dir<commit_after>// Copyright 2020 Google LLC
//
// 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 crate::bundle::{Bundle, Exchange, Request, Response, Uri, Version};
use crate::prelude::*;
use headers::{ContentLength, ContentType, HeaderMapExt as _, HeaderValue};
use http::StatusCode;
use std::path::{Path, PathBuf};
use url::Url;
use walkdir::WalkDir;

/// A Bundle builder.
#[derive(Default)]
pub struct Builder {
    version: Option<Version>,
    primary_url: Option<Uri>,
    manifest: Option<Uri>,
    exchanges: Vec<Exchange>,
}

impl Builder {
    pub(crate) fn new() -> Self {
        Default::default()
    }

    /// Sets the version.
    pub fn version(mut self, version: Version) -> Self {
        self.version = Some(version);
        self
    }

    /// Sets the primary url.
    pub fn primary_url(mut self, primary_url: Uri) -> Self {
        self.primary_url = Some(primary_url);
        self
    }

    /// Sets the manifest url.
    pub fn manifest(mut self, manifest: Uri) -> Self {
        self.manifest = Some(manifest);
        self
    }

    /// Adds the exchange.
    pub fn exchange(mut self, exchange: Exchange) -> Self {
        self.exchanges.push(exchange);
        self
    }

    /// Append exchanges from files rooted at the given directory.
    ///
    /// `base_url` will be used as a prefix for each resource. A relative path
    /// from the given directory to each file is appended to `base_url`.
    ///
    /// One exchange is created for each file, however, two exchanges
    /// are created for `index.html` file, as follows:
    ///
    /// 1. The pareent directory **serves** the contents of `index.html` file.
    /// 2. The URL for `index.html` file is a redirect to the parent directory
    ///    (`301` MOVED PERMANENTLY).
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use webbundle::{Bundle, Version};
    /// let bundle = Bundle::builder()
    ///     .version(Version::VersionB1)
    ///     .primary_url("https://example.com/".parse()?)
    ///     .exchanges_from_dir("build", "https://example.com".parse()?)?
    ///     .build()?;
    /// # Result::Ok::<(), anyhow::Error>(())
    /// ```
    pub fn exchanges_from_dir(mut self, dir: impl AsRef<Path>, base_url: Url) -> Result<Self> {
        self.exchanges.append(
            &mut ExchangeBuilder::new(PathBuf::from(dir.as_ref()), base_url)
                .walk()?
                .build(),
        );
        Ok(self)
    }

    /// Builds the bundle.
    pub fn build(self) -> Result<Bundle> {
        Ok(Bundle {
            version: self.version.context("no version")?,
            primary_url: self.primary_url.context("no primary_url")?,
            manifest: self.manifest,
            exchanges: self.exchanges,
        })
    }
}

#[allow(dead_code)]
struct ExchangeBuilder {
    base_url: Url,
    base_dir: PathBuf,
    exchanges: Vec<Exchange>,
}

#[allow(dead_code)]
impl ExchangeBuilder {
    fn new(base_dir: PathBuf, base_url: Url) -> Self {
        ExchangeBuilder {
            base_dir,
            base_url,
            exchanges: Vec::new(),
        }
    }

    fn walk(mut self) -> Result<Self> {
        for entry in WalkDir::new(&self.base_dir) {
            let entry = entry?;
            log::info!("visit: {:?}", entry);
            let file_type = entry.file_type();
            if file_type.is_symlink() {
                log::warn!(
                    "path is symbolink link. Skipping. {}",
                    entry.path().display()
                );
                continue;
            }
            if !file_type.is_file() {
                continue;
            }
            if entry.path().file_name().unwrap() == "index.html" {
                let dir = entry.path().parent().unwrap();

                let relative_url = pathdiff::diff_paths(dir, &self.base_dir).unwrap();
                let relative_path = pathdiff::diff_paths(entry.path(), &self.base_dir).unwrap();
                // for <dir> -> Serves the contents of <dir>/index.html
                self = self.exchange(&relative_url, &relative_path)?;

                // for <dir>/index.html -> redirect to "./"
                self = self.exchange_redirect(&relative_path, "./")?;
            } else {
                let relative_path = pathdiff::diff_paths(entry.path(), &self.base_dir).unwrap();
                self = self.exchange(&relative_path, &relative_path)?;
            }
        }
        Ok(self)
    }

    fn build(self) -> Vec<Exchange> {
        self.exchanges
    }

    fn url_from_relative_path(&self, relative_path: &Path) -> Result<Uri> {
        ensure!(
            relative_path.is_relative(),
            format!("Path is not relative: {}", relative_path.display())
        );
        Ok(self
            .base_url
            .join(&relative_path.display().to_string())?
            .to_string()
            .parse()?)
    }

    fn url_join(&self, relative_url: &str) -> Result<Uri> {
        Ok(self.base_url.join(relative_url)?.to_string().parse()?)
    }

    fn exchange(
        mut self,
        relative_url: impl AsRef<Path>,
        relative_path: impl AsRef<Path>,
    ) -> Result<Self> {
        self.exchanges.push(Exchange {
            request: Request::get(self.url_from_relative_path(relative_url.as_ref())?).body(())?,
            response: self.create_response(relative_path)?,
        });
        Ok(self)
    }

    fn exchange_redirect(mut self, relative_url: &Path, location: &str) -> Result<Self> {
        self.exchanges.push(Exchange {
            request: Request::get(self.url_from_relative_path(relative_url)?).body(())?,
            response: Self::create_redirect(location)?,
        });
        Ok(self)
    }

    fn create_redirect(location: &str) -> Result<Response> {
        let mut response = Response::new(Vec::new());
        *response.status_mut() = StatusCode::MOVED_PERMANENTLY;
        response
            .headers_mut()
            .insert("Location", HeaderValue::from_str(location)?);
        Ok(response)
    }

    fn create_response(&self, relative_path: impl AsRef<Path>) -> Result<Response> {
        ensure!(
            relative_path.as_ref().is_relative(),
            format!("Path is not relative: {}", relative_path.as_ref().display())
        );
        let path = self.base_dir.join(relative_path);
        let body = std::fs::read(&path)?;

        let content_length = ContentLength(body.len() as u64);
        let content_type = ContentType::from(mime_guess::from_path(&path).first_or_octet_stream());

        let mut response = Response::new(body);
        *response.status_mut() = StatusCode::OK;
        response.headers_mut().typed_insert(content_length);
        response.headers_mut().typed_insert(content_type);
        Ok(response)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashSet;

    #[test]
    fn build_fail() {
        assert!(Builder::new().build().is_err());
    }

    #[test]
    fn build() -> Result<()> {
        let bundle = Builder::new()
            .version(Version::Version1)
            .primary_url("https://example.com".parse()?)
            .build()?;
        assert_eq!(bundle.version, Version::Version1);
        assert_eq!(bundle.primary_url, "https://example.com".parse::<Uri>()?);
        Ok(())
    }

    #[test]
    fn exchange_builder() -> Result<()> {
        let base_dir = {
            let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
            path.push("tests/builder");
            path
        };

        let exchanges = ExchangeBuilder::new(base_dir.clone(), "https://example.com/".parse()?)
            .exchange(".", "index.html")?
            .build();
        assert_eq!(exchanges.len(), 1);
        let exchange = &exchanges[0];
        assert_eq!(
            exchange.request.uri(),
            &"https://example.com/".parse::<Uri>()?
        );
        assert_eq!(exchange.response.status(), StatusCode::OK);
        assert_eq!(exchange.response.headers()["content-type"], "text/html");
        assert_eq!(
            exchange.response.headers()["content-length"],
            std::fs::read(base_dir.join("index.html"))?
                .len()
                .to_string()
        );
        assert_eq!(
            exchange.response.body(),
            &std::fs::read(base_dir.join("index.html"))?
        );
        Ok(())
    }

    #[test]
    fn walk() -> Result<()> {
        let base_dir = {
            let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
            path.push("tests/builder");
            path
        };

        let exchanges = ExchangeBuilder::new(base_dir, "https://example.com/".parse()?)
            .walk()?
            .build();
        assert_eq!(exchanges.len(), 3);
        let urls = exchanges
            .into_iter()
            .map(|e| e.request.uri().to_string())
            .collect::<HashSet<_>>();
        assert!(urls.contains("https://example.com/"));
        assert!(urls.contains("https://example.com/index.html"));
        assert!(urls.contains("https://example.com/js/hello.js"));
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Thread safe communication channel implementing `Evented`

#![allow(unused_imports)]

use {io, Evented, Ready, Poll, PollOpt, Registration, SetReadiness, Token};
use lazycell::{LazyCell, AtomicLazyCell};
use std::sync::{mpsc, Arc};
use std::sync::atomic::{AtomicUsize, Ordering};

/// Creates a new asynchronous channel, where the `Receiver` can be registered
/// with `Poll`.
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
    let (tx_ctl, rx_ctl) = ctl_pair();
    let (tx, rx) = mpsc::channel();

    let tx = Sender {
        tx: tx,
        ctl: tx_ctl,
    };

    let rx = Receiver {
        rx: rx,
        ctl: rx_ctl,
    };

    (tx, rx)
}

/// Creates a new synchronous, bounded channel where the `Receiver` can be
/// registered with `Poll`.
pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
    let (tx_ctl, rx_ctl) = ctl_pair();
    let (tx, rx) = mpsc::sync_channel(bound);

    let tx = SyncSender {
        tx: tx,
        ctl: tx_ctl,
    };

    let rx = Receiver {
        rx: rx,
        ctl: rx_ctl,
    };

    (tx, rx)
}

pub fn ctl_pair() -> (SenderCtl, ReceiverCtl) {
    let inner = Arc::new(Inner {
        pending: AtomicUsize::new(0),
        senders: AtomicUsize::new(1),
        set_readiness: AtomicLazyCell::new(),
    });

    let tx = SenderCtl {
        inner: inner.clone(),
    };

    let rx = ReceiverCtl {
        registration: LazyCell::new(),
        inner: inner,
    };

    (tx, rx)
}

/// Tracks messages sent on a channel in order to update readiness.
pub struct SenderCtl {
    inner: Arc<Inner>,
}

/// Tracks messages received on a channel in order to track readiness.
pub struct ReceiverCtl {
    registration: LazyCell<Registration>,
    inner: Arc<Inner>,
}

pub struct Sender<T> {
    tx: mpsc::Sender<T>,
    ctl: SenderCtl,
}

pub struct SyncSender<T> {
    tx: mpsc::SyncSender<T>,
    ctl: SenderCtl,
}

pub struct Receiver<T> {
    rx: mpsc::Receiver<T>,
    ctl: ReceiverCtl,
}

#[derive(Debug)]
pub enum SendError<T> {
    Io(io::Error),
    Disconnected(T),
}

#[derive(Debug)]
pub enum TrySendError<T> {
    Io(io::Error),
    Full(T),
    Disconnected(T),
}

struct Inner {
    // The number of outstanding messages for the receiver to read
    pending: AtomicUsize,
    // The number of sender handles
    senders: AtomicUsize,
    // The set readiness handle
    set_readiness: AtomicLazyCell<SetReadiness>,
}

impl<T> Sender<T> {
    pub fn send(&self, t: T) -> Result<(), SendError<T>> {
        self.tx.send(t)
            .map_err(SendError::from)
            .and_then(|_| {
                try!(self.ctl.inc());
                Ok(())
            })
    }
}

impl<T> Clone for Sender<T> {
    fn clone(&self) -> Sender<T> {
        Sender {
            tx: self.tx.clone(),
            ctl: self.ctl.clone(),
        }
    }
}

impl<T> SyncSender<T> {
    pub fn send(&self, t: T) -> Result<(), SendError<T>> {
        self.tx.send(t)
            .map_err(From::from)
            .and_then(|_| {
                try!(self.ctl.inc());
                Ok(())
            })
    }

    pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
        self.tx.try_send(t)
            .map_err(From::from)
            .and_then(|_| {
                try!(self.ctl.inc());
                Ok(())
            })
    }
}

impl<T> Clone for SyncSender<T> {
    fn clone(&self) -> SyncSender<T> {
        SyncSender {
            tx: self.tx.clone(),
            ctl: self.ctl.clone(),
        }
    }
}

impl<T> Receiver<T> {
    pub fn try_recv(&self) -> Result<T, mpsc::TryRecvError> {
        self.rx.try_recv().and_then(|res| {
            let _ = self.ctl.dec();
            Ok(res)
        })
    }
}

impl<T> Evented for Receiver<T> {
    fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        self.ctl.register(poll, token, interest, opts)
    }

    fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        self.ctl.reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        self.ctl.deregister(poll)
    }
}

/*
 *
 * ===== SenderCtl / ReceiverCtl =====
 *
 */

impl SenderCtl {
    /// Call to track that a message has been sent
    pub fn inc(&self) -> io::Result<()> {
        let cnt = self.inner.pending.fetch_add(1, Ordering::Acquire);

        if 0 == cnt {
            // Toggle readiness to readable
            if let Some(set_readiness) = self.inner.set_readiness.borrow() {
                try!(set_readiness.set_readiness(Ready::readable()));
            }
        }

        Ok(())
    }
}

impl Clone for SenderCtl {
    fn clone(&self) -> SenderCtl {
        self.inner.senders.fetch_add(1, Ordering::Relaxed);
        SenderCtl { inner: self.inner.clone() }
    }
}

impl Drop for SenderCtl {
    fn drop(&mut self) {
        if self.inner.senders.fetch_sub(1, Ordering::Release) == 1 {
            let _ = self.inc();
        }
    }
}

impl ReceiverCtl {
    pub fn dec(&self) -> io::Result<()> {
        let first = self.inner.pending.load(Ordering::Acquire);

        if first == 1 {
            // Unset readiness
            if let Some(set_readiness) = self.inner.set_readiness.borrow() {
                try!(set_readiness.set_readiness(Ready::none()));
            }
        }

        // Decrement
        let second = self.inner.pending.fetch_sub(1, Ordering::AcqRel);

        if first == 1 && second > 0 {
            // There are still pending messages. Since readiness was
            // previously unset, it must be reset here
            if let Some(set_readiness) = self.inner.set_readiness.borrow() {
                try!(set_readiness.set_readiness(Ready::none()));
            }
        }

        Ok(())
    }
}

impl Evented for ReceiverCtl {
    fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        if self.registration.borrow().is_some() {
            return Err(io::Error::new(io::ErrorKind::Other, "receiver already registered"));
        }

        let (registration, set_readiness) = Registration::new(poll, token, interest, opts);

        if self.inner.pending.load(Ordering::Relaxed) > 0 {
            // TODO: Don't drop readiness
            let _ = set_readiness.set_readiness(Ready::readable());
        }

        self.registration.fill(registration).ok().expect("unexpected state encountered");
        self.inner.set_readiness.fill(set_readiness).ok().expect("unexpected state encountered");

        Ok(())
    }

    fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        match self.registration.borrow() {
            Some(registration) => registration.update(poll, token, interest, opts),
            None => Err(io::Error::new(io::ErrorKind::Other, "receiver not registered")),
        }
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        match self.registration.borrow() {
            Some(registration) => registration.deregister(poll),
            None => Err(io::Error::new(io::ErrorKind::Other, "receiver not registered")),
        }
    }
}

/*
 *
 * ===== Error conversions =====
 *
 */

impl<T> From<mpsc::SendError<T>> for SendError<T> {
    fn from(src: mpsc::SendError<T>) -> SendError<T> {
        SendError::Disconnected(src.0)
    }
}

impl<T> From<io::Error> for SendError<T> {
    fn from(src: io::Error) -> SendError<T> {
        SendError::Io(src)
    }
}

impl<T> From<mpsc::TrySendError<T>> for TrySendError<T> {
    fn from(src: mpsc::TrySendError<T>) -> TrySendError<T> {
        match src {
            mpsc::TrySendError::Full(v) => TrySendError::Full(v),
            mpsc::TrySendError::Disconnected(v) => TrySendError::Disconnected(v),
        }
    }
}

impl<T> From<mpsc::SendError<T>> for TrySendError<T> {
    fn from(src: mpsc::SendError<T>) -> TrySendError<T> {
        TrySendError::Disconnected(src.0)
    }
}

impl<T> From<io::Error> for TrySendError<T> {
    fn from(src: io::Error) -> TrySendError<T> {
        TrySendError::Io(src)
    }
}
<commit_msg>Fix channel `dec` logic<commit_after>//! Thread safe communication channel implementing `Evented`

#![allow(unused_imports)]

use {io, Evented, Ready, Poll, PollOpt, Registration, SetReadiness, Token};
use lazycell::{LazyCell, AtomicLazyCell};
use std::sync::{mpsc, Arc};
use std::sync::atomic::{AtomicUsize, Ordering};

/// Creates a new asynchronous channel, where the `Receiver` can be registered
/// with `Poll`.
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
    let (tx_ctl, rx_ctl) = ctl_pair();
    let (tx, rx) = mpsc::channel();

    let tx = Sender {
        tx: tx,
        ctl: tx_ctl,
    };

    let rx = Receiver {
        rx: rx,
        ctl: rx_ctl,
    };

    (tx, rx)
}

/// Creates a new synchronous, bounded channel where the `Receiver` can be
/// registered with `Poll`.
pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
    let (tx_ctl, rx_ctl) = ctl_pair();
    let (tx, rx) = mpsc::sync_channel(bound);

    let tx = SyncSender {
        tx: tx,
        ctl: tx_ctl,
    };

    let rx = Receiver {
        rx: rx,
        ctl: rx_ctl,
    };

    (tx, rx)
}

pub fn ctl_pair() -> (SenderCtl, ReceiverCtl) {
    let inner = Arc::new(Inner {
        pending: AtomicUsize::new(0),
        senders: AtomicUsize::new(1),
        set_readiness: AtomicLazyCell::new(),
    });

    let tx = SenderCtl {
        inner: inner.clone(),
    };

    let rx = ReceiverCtl {
        registration: LazyCell::new(),
        inner: inner,
    };

    (tx, rx)
}

/// Tracks messages sent on a channel in order to update readiness.
pub struct SenderCtl {
    inner: Arc<Inner>,
}

/// Tracks messages received on a channel in order to track readiness.
pub struct ReceiverCtl {
    registration: LazyCell<Registration>,
    inner: Arc<Inner>,
}

pub struct Sender<T> {
    tx: mpsc::Sender<T>,
    ctl: SenderCtl,
}

pub struct SyncSender<T> {
    tx: mpsc::SyncSender<T>,
    ctl: SenderCtl,
}

pub struct Receiver<T> {
    rx: mpsc::Receiver<T>,
    ctl: ReceiverCtl,
}

#[derive(Debug)]
pub enum SendError<T> {
    Io(io::Error),
    Disconnected(T),
}

#[derive(Debug)]
pub enum TrySendError<T> {
    Io(io::Error),
    Full(T),
    Disconnected(T),
}

struct Inner {
    // The number of outstanding messages for the receiver to read
    pending: AtomicUsize,
    // The number of sender handles
    senders: AtomicUsize,
    // The set readiness handle
    set_readiness: AtomicLazyCell<SetReadiness>,
}

impl<T> Sender<T> {
    pub fn send(&self, t: T) -> Result<(), SendError<T>> {
        self.tx.send(t)
            .map_err(SendError::from)
            .and_then(|_| {
                try!(self.ctl.inc());
                Ok(())
            })
    }
}

impl<T> Clone for Sender<T> {
    fn clone(&self) -> Sender<T> {
        Sender {
            tx: self.tx.clone(),
            ctl: self.ctl.clone(),
        }
    }
}

impl<T> SyncSender<T> {
    pub fn send(&self, t: T) -> Result<(), SendError<T>> {
        self.tx.send(t)
            .map_err(From::from)
            .and_then(|_| {
                try!(self.ctl.inc());
                Ok(())
            })
    }

    pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
        self.tx.try_send(t)
            .map_err(From::from)
            .and_then(|_| {
                try!(self.ctl.inc());
                Ok(())
            })
    }
}

impl<T> Clone for SyncSender<T> {
    fn clone(&self) -> SyncSender<T> {
        SyncSender {
            tx: self.tx.clone(),
            ctl: self.ctl.clone(),
        }
    }
}

impl<T> Receiver<T> {
    pub fn try_recv(&self) -> Result<T, mpsc::TryRecvError> {
        self.rx.try_recv().and_then(|res| {
            let _ = self.ctl.dec();
            Ok(res)
        })
    }
}

impl<T> Evented for Receiver<T> {
    fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        self.ctl.register(poll, token, interest, opts)
    }

    fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        self.ctl.reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        self.ctl.deregister(poll)
    }
}

/*
 *
 * ===== SenderCtl / ReceiverCtl =====
 *
 */

impl SenderCtl {
    /// Call to track that a message has been sent
    pub fn inc(&self) -> io::Result<()> {
        let cnt = self.inner.pending.fetch_add(1, Ordering::Acquire);

        if 0 == cnt {
            // Toggle readiness to readable
            if let Some(set_readiness) = self.inner.set_readiness.borrow() {
                try!(set_readiness.set_readiness(Ready::readable()));
            }
        }

        Ok(())
    }
}

impl Clone for SenderCtl {
    fn clone(&self) -> SenderCtl {
        self.inner.senders.fetch_add(1, Ordering::Relaxed);
        SenderCtl { inner: self.inner.clone() }
    }
}

impl Drop for SenderCtl {
    fn drop(&mut self) {
        if self.inner.senders.fetch_sub(1, Ordering::Release) == 1 {
            let _ = self.inc();
        }
    }
}

impl ReceiverCtl {
    pub fn dec(&self) -> io::Result<()> {
        let first = self.inner.pending.load(Ordering::Acquire);

        if first == 1 {
            // Unset readiness
            if let Some(set_readiness) = self.inner.set_readiness.borrow() {
                try!(set_readiness.set_readiness(Ready::none()));
            }
        }

        // Decrement
        let second = self.inner.pending.fetch_sub(1, Ordering::AcqRel);

        if first == 1 && second > 1 {
            // There are still pending messages. Since readiness was
            // previously unset, it must be reset here
            if let Some(set_readiness) = self.inner.set_readiness.borrow() {
                try!(set_readiness.set_readiness(Ready::readable()));
            }
        }

        Ok(())
    }
}

impl Evented for ReceiverCtl {
    fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        if self.registration.borrow().is_some() {
            return Err(io::Error::new(io::ErrorKind::Other, "receiver already registered"));
        }

        let (registration, set_readiness) = Registration::new(poll, token, interest, opts);

        if self.inner.pending.load(Ordering::Relaxed) > 0 {
            // TODO: Don't drop readiness
            let _ = set_readiness.set_readiness(Ready::readable());
        }

        self.registration.fill(registration).ok().expect("unexpected state encountered");
        self.inner.set_readiness.fill(set_readiness).ok().expect("unexpected state encountered");

        Ok(())
    }

    fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        match self.registration.borrow() {
            Some(registration) => registration.update(poll, token, interest, opts),
            None => Err(io::Error::new(io::ErrorKind::Other, "receiver not registered")),
        }
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        match self.registration.borrow() {
            Some(registration) => registration.deregister(poll),
            None => Err(io::Error::new(io::ErrorKind::Other, "receiver not registered")),
        }
    }
}

/*
 *
 * ===== Error conversions =====
 *
 */

impl<T> From<mpsc::SendError<T>> for SendError<T> {
    fn from(src: mpsc::SendError<T>) -> SendError<T> {
        SendError::Disconnected(src.0)
    }
}

impl<T> From<io::Error> for SendError<T> {
    fn from(src: io::Error) -> SendError<T> {
        SendError::Io(src)
    }
}

impl<T> From<mpsc::TrySendError<T>> for TrySendError<T> {
    fn from(src: mpsc::TrySendError<T>) -> TrySendError<T> {
        match src {
            mpsc::TrySendError::Full(v) => TrySendError::Full(v),
            mpsc::TrySendError::Disconnected(v) => TrySendError::Disconnected(v),
        }
    }
}

impl<T> From<mpsc::SendError<T>> for TrySendError<T> {
    fn from(src: mpsc::SendError<T>) -> TrySendError<T> {
        TrySendError::Disconnected(src.0)
    }
}

impl<T> From<io::Error> for TrySendError<T> {
    fn from(src: io::Error) -> TrySendError<T> {
        TrySendError::Io(src)
    }
}
<|endoftext|>


<commit_before>
use std::io;
use std::clone::Clone;
use std::slice::Iter;

use linked_hash_map::LinkedHashMap;

use parser::ast::*;
use parser::util::*;
use processing::structs::*;
use output::client_ops_stream_writer::*;
use output::client_misc::*;
use output::scope::*;

#[derive(Debug)]
pub struct BlockDefinition {
    pub block_id: String,
    pub ops: Vec<ElementOp>
}
pub type BlockMap = LinkedHashMap<String, BlockDefinition>;

pub struct ElementOpsWriter<'input: 'scope, 'scope> {
    pub doc: &'input DocumentState<'input>,
    pub stream_writer: &'scope mut ElementOpsStreamWriter,
    pub scopes: LinkedHashMap<String, ElementOpScope>,
    pub blocks: BlockMap,
    pub cur_block_id: Option<String>
}

impl<'input: 'scope, 'scope> ElementOpsWriter<'input, 'scope> {

    pub fn with_doc(doc: &'input DocumentState<'input>, stream_writer: &'scope mut ElementOpsStreamWriter) -> Self {
        ElementOpsWriter {
            doc: doc,
            stream_writer: stream_writer,
            scopes: Default::default(),
            blocks: Default::default(),
            cur_block_id: None
        }
    }

    #[inline]
    fn write_loop_item(&mut self, w: &mut io::Write, doc: &'input DocumentState, item_expr: &ExprValue, scope: &ElementOpScope, ele: Option<&str>, element_ty: Option<&VarType>, block_id: &str, output_component_contents: bool) -> Result {
        let mut scope = scope.clone();

        if let Some(ele_key) = ele {
            scope.add_loop_var_with_value(ele_key, item_expr);

            // loop_scope.1.symbol_map.insert(ele_key.to_owned(), (Some(SymbolReferenceType::LoopVarReference(ele_key.to_owned())), None));
            // loop_scope = loop_scope
            //     .with_var(ele_key,
            //         SymbolReferenceType::LoopVarReference(ele_key.to_owned()),
            //         element_ty.as_ref().map(Clone::clone),
            //         Some(SymbolValueType::ConstantValue(item_expr.clone()))
            //     );
        };

        let block_ops = self.blocks.get(block_id)
            .map(|block| block.ops.clone());

        if let Some(ref block_ops) = block_ops {
            // Push scope
            let scope_id = format!("{}_{}", scope.0.key_prefix(block_id), 1);
            self.scopes.insert(scope_id, scope.clone());

            // Output ops
            self.write_ops_content(w, block_ops.iter(), doc, &scope, output_component_contents)?;

            // Pop scope
            self.scopes.pop_back();
        };
        Ok(())
    }

    #[inline]
    fn invoke_component_with_props(&mut self, w: &mut io::Write, doc: &'input DocumentState, scope: &ElementOpScope, comp: &Component, props: Option<Iter<Prop>>, output_component_contents: bool) -> Result {
        let mut scope = scope.clone();

        if let Some(props) = props {
            for &(ref key, ref expr) in props {
                if let Some(ref expr) = expr.as_ref().and_then(|expr| reduce_expr(&expr, doc, &scope)) {
                    scope.add_prop_with_value(key, &expr);
                };
            }
        };

        // TODO: Restore props from Component object

        let scope_key = allocate_element_key();
        let scope_id = scope.0.key_prefix(&scope_key);
        self.scopes.insert(scope_id, scope.clone());

        if let Some(ref ops) = comp.ops {
            self.write_ops_content(w, ops.iter(), doc, &scope, output_component_contents)?;
        };
        Ok(())
    }

    #[inline]
    #[allow(dead_code)]
    pub fn write_single_component_instance(&mut self, w: &mut io::Write, op: &ElementOp, doc: &'input DocumentState, scope: &ElementOpScope, comp: &Component, component_key: &str, props: Option<Iter<Prop>>, lens: Option<&LensExprType>, loop_iteration: Option<(&Symbol, i32)>, output_component_contents: bool) -> Result {
        let mut component_id =  format!("{}", component_key);
        // let mut props: Vec<Prop> = props.collect();

        let mut scope = scope.clone();

        let props_iter = props.as_ref().map(|s| s.clone());
        if let Some(props_iter) = props_iter {
            for &(ref key, ref expr) in props_iter {
                if let &Some(ref expr) = expr {
                    if let Some(expr) = reduce_expr(&expr, doc, &scope) {
                        scope.add_prop_with_value(&key, &expr);
                    };
                }
            }
        };

        if let Some(ref loop_iteration) = loop_iteration {
            let loop_idx = loop_iteration.1;
            let loopidx_ref = Symbol::loop_idx("foridx", &component_id);

            component_id = format!("{}_{}", component_id, loop_idx);
            let key_suffix = format!("{}", loop_idx);
            scope.0 = add_key_prefix(&scope.0, &key_suffix);
            scope.0 = with_key_expr_prefix(&scope.0, ExprValue::SymbolReference(loopidx_ref));
        };

        // let props_iter = props.as_ref().map(|s| s.iter());

        // OpenS
        let props_iter = props.as_ref().map(|s| s.clone());
        self.stream_writer.write_op_element_instance_component_open(w, op, doc, &scope, &comp, component_key, component_id.as_str(), props_iter, lens)?;

        if output_component_contents {
            let props_iter = props.as_ref().map(|s| s.clone());
            self.invoke_component_with_props(w, doc, &scope, comp, props_iter, true)?;
            // if let Some(ref ops) = comp.ops {
            //     self.write_ops_content(w, ops.iter(), doc, &scope, output_component_contents)?;
            // };
        };

        // Close
        self.stream_writer.write_op_element_instance_component_close(w, op, doc, &scope, &comp, component_key, component_id.as_str())?;

        Ok(())
    }

    #[inline]
    #[allow(unused_variables)]
    pub fn write_ops_content<'op>(&mut self, w: &mut io::Write, ops: Iter<'op, ElementOp>, doc: &'input DocumentState, scope: &ElementOpScope, output_component_contents: bool) -> Result {
        for op in ops {
            let mut scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

            if output_component_contents {
                if let &ElementOp::EndBlock(..) = op {
                    self.cur_block_id = None;
                    continue;
                };

                if let Some(ref cur_block_id) = self.cur_block_id {
                    let block = self.blocks.entry(cur_block_id.to_owned())
                        .or_insert_with(|| BlockDefinition { block_id: cur_block_id.clone(), ops: Default::default() });

                    block.ops.push(op.clone());
                    continue;
                };
            };

            let is_void = if let &ElementOp::ElementVoid(..) = op { true } else { false };

            match op {
                &ElementOp::ElementOpen(ref element_tag, ref element_key, ref attrs, ref events) |
                &ElementOp::ElementVoid(ref element_tag, ref element_key, ref attrs, ref events) => {
                    let element_key = element_key.as_ref().map_or("null", |s| s);

                    let attrs = attrs.as_ref().map(|attrs| attrs.iter());
                    let events = events.as_ref().map(|events| events.iter());

                    let element_key = format!("{}", scope.0.key_prefix(element_key));
                    self.stream_writer.write_op_element(w, op, doc, &scope, &element_key, element_tag, is_void, attrs, events)?;
                }
                &ElementOp::ElementClose(ref element_tag) => {
                    // let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                    self.stream_writer.write_op_element_close(w, op, doc, &scope, element_tag)?;
                }
                &ElementOp::WriteValue(ref expr, ref value_key) => {
                    // let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                    let value_key = value_key.as_ref().map_or("null", |s| s);
                    self.stream_writer.write_op_element_value(w, op, doc, &scope, expr, value_key)?;
                }
                &ElementOp::InstanceComponent(ref component_ty,
                                            ref component_key,
                                            ref props,
                                            ref lens) => {
                    let comp = doc.comp_map.get(component_ty.as_str());
                    if let Some(ref comp) = comp {
                        let component_key = component_key.as_ref().map_or("null", |s| s);
                        let component_id = format!("{}_1", component_key);

                        match lens {
                            &Some(LensExprType::ForLens(ref ele_key, ref coll_sym)) => {
                                let coll_expr = ExprValue::SymbolReference(coll_sym.clone());
                                let coll_expr = reduce_expr(&coll_expr, doc, &scope);

                                // if output_component_contents {
                                    if let Some(ExprValue::LiteralArray(Some(ref items))) = coll_expr {
                                        for item_expr in items {
                                            // let ele_key = ele_key.as_ref().map(|s| s.as_str());
                                            // self.write_loop_item(w, doc, item_expr, &scope, ele_key, None, &component_id, output_component_contents)?;
                                            // let props_iter = props.as_ref().map(|p| p.iter());

                                            let mut props = props.as_ref().map_or(vec![], |p| p.clone());
                                            if let &Some(ref ele_key) = ele_key {
                                                let expr = ExprValue::SymbolReference(Symbol::prop(&ele_key));
                                                props.push((ele_key.to_owned(), Some(expr)));

                                                let mut scope = scope.clone();
                                                scope.1.add_param(ele_key);

                                                let ele_sym = Symbol::prop(ele_key);
                                                self.write_single_component_instance(w, op, doc, &scope, comp, component_key, Some(props.iter()), lens.as_ref(), Some((&ele_sym, 1)), output_component_contents)?;

                                                continue;
                                            };
                                            self.write_single_component_instance(w, op, doc, &scope, comp, component_key, Some(props.iter()), None, None, output_component_contents)?;
                                        };
                                    };
                                // } else {
                                // };
                            }

                            &Some(LensExprType::GetLens(ref sym)) => {
                                let props_iter = props.as_ref().map(|p| p.iter());
                                self.write_single_component_instance(w, op, doc, &scope, comp, component_key, props_iter, None, None, output_component_contents)?;
                            }

                            _ => {
                                let props_iter = props.as_ref().map(|p| p.iter());
                                self.write_single_component_instance(w, op, doc, &scope, comp, component_key, props_iter, None, None, output_component_contents)?;
                            }
                        };

                        // let props = props.as_ref().map(|s| s.clone());
                        // let lens = lens.as_ref().map(|s| s.clone());

                        // let props_iter = props.as_ref().map(|s| s.iter());

                        // // OpenS
                        // self.stream_writer.write_op_element_instance_component_open(w, op, doc, &scope, &comp, component_key, component_id.as_str(), props_iter.as_ref().map(Clone::clone), lens.as_ref())?;

                        // if output_component_contents {
                        //     self.invoke_component_with_props(w, doc, &scope, comp, props_iter.as_ref().map(Clone::clone), true)?;
                        //     // if let Some(ref ops) = comp.ops {
                        //     //     self.write_ops_content(w, ops.iter(), doc, &scope, output_component_contents)?;
                        //     // };
                        // };

                        // // Close
                        // self.stream_writer.write_op_element_instance_component_close(w, op, doc, &scope, &comp, component_key, component_id.as_str())?;
                    }
                }

                &ElementOp::StartBlock(ref block_id) => {
                    if output_component_contents {
                        // Collect blocks to render
                        self.cur_block_id = Some(block_id.to_owned());
                    } else {
                        // Write function header
                        let loopidx_ref = Symbol::loop_idx("foridx", block_id);
                        scope.0 = with_key_expr_prefix(&scope.0, ExprValue::SymbolReference(loopidx_ref));
                        self.stream_writer.write_op_element_start_block(w, op, doc, &scope, block_id)?;

                        let scope_id = scope.0.key_prefix(block_id);
                        self.scopes.insert(scope_id, scope.clone());
                    };
                }

                &ElementOp::EndBlock(ref block_id) => {
                    if output_component_contents {
                        // Finish current block
                        self.cur_block_id = None;
                    } else {
                        self.scopes.pop_back();
                        let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                        self.stream_writer.write_op_element_end_block(w, op, doc, &scope, block_id)?;
                    };
                }

                &ElementOp::MapCollection(ref block_id, ref ele, ref coll_expr) => {
                    if output_component_contents {
                        let scope = self.scopes.back().unwrap().1.clone();
                        // let mut scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                        let has_block = self.blocks.contains_key(block_id);
                        if has_block {
                            let ele = ele.as_ref().map(|e| e.as_str());

                            let coll_expr = reduce_expr(coll_expr, doc, &scope);

                            if let Some(ExprValue::LiteralArray(Some(ref items))) = coll_expr {
                                for item_expr in items {
                                    self.write_loop_item(w, doc, item_expr, &scope, ele, None, block_id, output_component_contents)?;
                                };
                            };
                        };
                    } else {
                        let forvar_default = &format!("__forvar_{}", block_id);
                        let scope_id = format!("{}_map", block_id);

                        // Map to block
                        self.stream_writer.write_op_element_map_collection_to_block(w, op, doc, &scope, coll_expr, block_id)?;
                    };
                }
            }
        }

        Ok(())
    }
}<commit_msg>Fix rendering of test_output5<commit_after>
use std::io;
use std::clone::Clone;
use std::slice::Iter;

use linked_hash_map::LinkedHashMap;

use parser::ast::*;
use parser::util::*;
use processing::structs::*;
use output::client_ops_stream_writer::*;
use output::client_misc::*;
use output::scope::*;

#[derive(Debug)]
pub struct BlockDefinition {
    pub block_id: String,
    pub ops: Vec<ElementOp>
}
pub type BlockMap = LinkedHashMap<String, BlockDefinition>;

pub struct ElementOpsWriter<'input: 'scope, 'scope> {
    pub doc: &'input DocumentState<'input>,
    pub stream_writer: &'scope mut ElementOpsStreamWriter,
    pub scopes: LinkedHashMap<String, ElementOpScope>,
    pub blocks: BlockMap,
    pub cur_block_id: Option<String>
}

impl<'input: 'scope, 'scope> ElementOpsWriter<'input, 'scope> {

    pub fn with_doc(doc: &'input DocumentState<'input>, stream_writer: &'scope mut ElementOpsStreamWriter) -> Self {
        ElementOpsWriter {
            doc: doc,
            stream_writer: stream_writer,
            scopes: Default::default(),
            blocks: Default::default(),
            cur_block_id: None
        }
    }

    #[inline]
    fn write_loop_item(&mut self, w: &mut io::Write, doc: &'input DocumentState, item_expr: &ExprValue, scope: &ElementOpScope, ele: Option<&str>, element_ty: Option<&VarType>, block_id: &str, output_component_contents: bool) -> Result {
        let mut scope = scope.clone();

        if let Some(ele_key) = ele {
            scope.add_loop_var_with_value(ele_key, item_expr);

            // loop_scope.1.symbol_map.insert(ele_key.to_owned(), (Some(SymbolReferenceType::LoopVarReference(ele_key.to_owned())), None));
            // loop_scope = loop_scope
            //     .with_var(ele_key,
            //         SymbolReferenceType::LoopVarReference(ele_key.to_owned()),
            //         element_ty.as_ref().map(Clone::clone),
            //         Some(SymbolValueType::ConstantValue(item_expr.clone()))
            //     );
        };

        let block_ops = self.blocks.get(block_id)
            .map(|block| block.ops.clone());

        if let Some(ref block_ops) = block_ops {
            // Push scope
            let scope_id = format!("{}_{}", scope.0.key_prefix(block_id), 1);
            self.scopes.insert(scope_id, scope.clone());

            // Output ops
            self.write_ops_content(w, block_ops.iter(), doc, &scope, output_component_contents)?;

            // Pop scope
            self.scopes.pop_back();
        };
        Ok(())
    }

    #[inline]
    fn invoke_component_with_props(&mut self, w: &mut io::Write, doc: &'input DocumentState, scope: &ElementOpScope, comp: &Component, props: Option<Iter<Prop>>, output_component_contents: bool) -> Result {
        let mut scope = scope.clone();

        if let Some(props) = props {
            for &(ref key, ref expr) in props {
                if let Some(ref expr) = expr.as_ref().and_then(|expr| reduce_expr(&expr, doc, &scope)) {
                    scope.add_prop_with_value(key, &expr);
                };
            }
        };

        // TODO: Restore props from Component object

        let scope_key = allocate_element_key();
        let scope_id = scope.0.key_prefix(&scope_key);
        self.scopes.insert(scope_id, scope.clone());

        if let Some(ref ops) = comp.ops {
            self.write_ops_content(w, ops.iter(), doc, &scope, output_component_contents)?;
        };
        Ok(())
    }

    #[inline]
    #[allow(dead_code)]
    pub fn write_single_component_instance(&mut self, w: &mut io::Write, op: &ElementOp, doc: &'input DocumentState, scope: &ElementOpScope, comp: &Component, component_key: &str, props: Option<Iter<Prop>>, lens: Option<&LensExprType>, loop_iteration: Option<(&Symbol, i32)>, output_component_contents: bool) -> Result {
        let mut component_id =  format!("{}", component_key);
        // let mut props: Vec<Prop> = props.collect();

        let mut scope = scope.clone();

        let props_iter = props.as_ref().map(|s| s.clone());
        if let Some(props_iter) = props_iter {
            for &(ref key, ref expr) in props_iter {
                if let &Some(ref expr) = expr {
                    if let Some(expr) = reduce_expr(&expr, doc, &scope) {
                        scope.add_prop_with_value(&key, &expr);
                    };
                }
            }
        };

        if let Some(ref loop_iteration) = loop_iteration {
            let loop_idx = loop_iteration.1;
            let loopidx_ref = Symbol::loop_idx("foridx", &component_id);

            component_id = format!("{}_{}", component_id, loop_idx);
            let key_suffix = format!("{}", loop_idx);
            scope.0 = add_key_prefix(&scope.0, &key_suffix);
            scope.0 = with_key_expr_prefix(&scope.0, ExprValue::SymbolReference(loopidx_ref));
        };

        // let props_iter = props.as_ref().map(|s| s.iter());

        // OpenS
        let props_iter = props.as_ref().map(|s| s.clone());
        self.stream_writer.write_op_element_instance_component_open(w, op, doc, &scope, &comp, component_key, component_id.as_str(), props_iter, lens)?;

        if output_component_contents {
            let props_iter = props.as_ref().map(|s| s.clone());
            self.invoke_component_with_props(w, doc, &scope, comp, props_iter, true)?;
            // if let Some(ref ops) = comp.ops {
            //     self.write_ops_content(w, ops.iter(), doc, &scope, output_component_contents)?;
            // };
        };

        // Close
        self.stream_writer.write_op_element_instance_component_close(w, op, doc, &scope, &comp, component_key, component_id.as_str())?;

        Ok(())
    }

    #[inline]
    #[allow(unused_variables)]
    pub fn write_ops_content<'op>(&mut self, w: &mut io::Write, ops: Iter<'op, ElementOp>, doc: &'input DocumentState, scope: &ElementOpScope, output_component_contents: bool) -> Result {
        for op in ops {
            let mut scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

            if output_component_contents {
                if let &ElementOp::EndBlock(..) = op {
                    self.cur_block_id = None;
                    continue;
                };

                if let Some(ref cur_block_id) = self.cur_block_id {
                    let block = self.blocks.entry(cur_block_id.to_owned())
                        .or_insert_with(|| BlockDefinition { block_id: cur_block_id.clone(), ops: Default::default() });

                    block.ops.push(op.clone());
                    continue;
                };
            };

            let is_void = if let &ElementOp::ElementVoid(..) = op { true } else { false };

            match op {
                &ElementOp::ElementOpen(ref element_tag, ref element_key, ref attrs, ref events) |
                &ElementOp::ElementVoid(ref element_tag, ref element_key, ref attrs, ref events) => {
                    let element_key = element_key.as_ref().map_or("null", |s| s);

                    let attrs = attrs.as_ref().map(|attrs| attrs.iter());
                    let events = events.as_ref().map(|events| events.iter());

                    let element_key = format!("{}", scope.0.key_prefix(element_key));
                    self.stream_writer.write_op_element(w, op, doc, &scope, &element_key, element_tag, is_void, attrs, events)?;
                }
                &ElementOp::ElementClose(ref element_tag) => {
                    // let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                    self.stream_writer.write_op_element_close(w, op, doc, &scope, element_tag)?;
                }
                &ElementOp::WriteValue(ref expr, ref value_key) => {
                    // let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                    let value_key = value_key.as_ref().map_or("null", |s| s);
                    self.stream_writer.write_op_element_value(w, op, doc, &scope, expr, value_key)?;
                }
                &ElementOp::InstanceComponent(ref component_ty,
                                            ref component_key,
                                            ref props,
                                            ref lens) => {
                    let comp = doc.comp_map.get(component_ty.as_str());
                    if let Some(ref comp) = comp {
                        let component_key = component_key.as_ref().map_or("null", |s| s);
                        let component_id = format!("{}_1", component_key);

                        match lens {
                            &Some(LensExprType::ForLens(ref ele_key, ref coll_sym)) => {
                                let coll_expr = ExprValue::SymbolReference(coll_sym.clone());
                                let coll_expr = reduce_expr(&coll_expr, doc, &scope);

                                let mut props = props.as_ref().map_or(vec![], |p| p.clone());

                                if let &Some(ref ele_key) = ele_key {

                                    // Prepare scope and props
                                    let expr = ExprValue::SymbolReference(Symbol::prop(&ele_key));
                                    props.push((ele_key.to_owned(), Some(expr)));

                                    let mut scope = scope.clone();
                                    scope.1.add_param(ele_key);

                                    if output_component_contents {
                                        if let Some(ExprValue::LiteralArray(Some(ref items))) = coll_expr {
                                            for item_expr in items {
                                                let ele_sym = Symbol::prop(ele_key);
                                                scope.1.add_prop_with_value(ele_key, item_expr);
                                                self.write_single_component_instance(w, op, doc, &scope, comp, component_key, Some(props.iter()), lens.as_ref(), Some((&ele_sym, 1)), output_component_contents)?;
                                            };
                                        };
                                    } else {
                                        self.write_single_component_instance(w, op, doc, &scope, comp, component_key, Some(props.iter()), lens.as_ref(), None, output_component_contents)?;
                                    };
                                };
                            }

                            &Some(LensExprType::GetLens(ref sym)) => {
                                let props_iter = props.as_ref().map(|p| p.iter());
                                self.write_single_component_instance(w, op, doc, &scope, comp, component_key, props_iter, None, None, output_component_contents)?;
                            }

                            _ => {
                                let props_iter = props.as_ref().map(|p| p.iter());
                                self.write_single_component_instance(w, op, doc, &scope, comp, component_key, props_iter, None, None, output_component_contents)?;
                            }
                        };

                        // let props = props.as_ref().map(|s| s.clone());
                        // let lens = lens.as_ref().map(|s| s.clone());

                        // let props_iter = props.as_ref().map(|s| s.iter());

                        // // OpenS
                        // self.stream_writer.write_op_element_instance_component_open(w, op, doc, &scope, &comp, component_key, component_id.as_str(), props_iter.as_ref().map(Clone::clone), lens.as_ref())?;

                        // if output_component_contents {
                        //     self.invoke_component_with_props(w, doc, &scope, comp, props_iter.as_ref().map(Clone::clone), true)?;
                        //     // if let Some(ref ops) = comp.ops {
                        //     //     self.write_ops_content(w, ops.iter(), doc, &scope, output_component_contents)?;
                        //     // };
                        // };

                        // // Close
                        // self.stream_writer.write_op_element_instance_component_close(w, op, doc, &scope, &comp, component_key, component_id.as_str())?;
                    }
                }

                &ElementOp::StartBlock(ref block_id) => {
                    if output_component_contents {
                        // Collect blocks to render
                        self.cur_block_id = Some(block_id.to_owned());
                    } else {
                        // Write function header
                        let loopidx_ref = Symbol::loop_idx("foridx", block_id);
                        scope.0 = with_key_expr_prefix(&scope.0, ExprValue::SymbolReference(loopidx_ref));
                        self.stream_writer.write_op_element_start_block(w, op, doc, &scope, block_id)?;

                        let scope_id = scope.0.key_prefix(block_id);
                        self.scopes.insert(scope_id, scope.clone());
                    };
                }

                &ElementOp::EndBlock(ref block_id) => {
                    if output_component_contents {
                        // Finish current block
                        self.cur_block_id = None;
                    } else {
                        self.scopes.pop_back();
                        let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                        self.stream_writer.write_op_element_end_block(w, op, doc, &scope, block_id)?;
                    };
                }

                &ElementOp::MapCollection(ref block_id, ref ele, ref coll_expr) => {
                    if output_component_contents {
                        let scope = self.scopes.back().unwrap().1.clone();
                        // let mut scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                        let has_block = self.blocks.contains_key(block_id);
                        if has_block {
                            let ele = ele.as_ref().map(|e| e.as_str());

                            let coll_expr = reduce_expr(coll_expr, doc, &scope);

                            if let Some(ExprValue::LiteralArray(Some(ref items))) = coll_expr {
                                for item_expr in items {
                                    self.write_loop_item(w, doc, item_expr, &scope, ele, None, block_id, output_component_contents)?;
                                };
                            };
                        };
                    } else {
                        let forvar_default = &format!("__forvar_{}", block_id);
                        let scope_id = format!("{}_map", block_id);

                        // Map to block
                        self.stream_writer.write_op_element_map_collection_to_block(w, op, doc, &scope, coll_expr, block_id)?;
                    };
                }
            }
        }

        Ok(())
    }
}<|endoftext|>


<commit_before>use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::{au, px_to_au};
use libc::{c_void};
use font_library::FontLibrary;
use font::Font;
use glyph::Glyph;
use shaper::shape_text;

#[doc="A single, unbroken line of text."]
struct TextRun {
    priv glyphs: ~[Glyph],
    priv size_: Size2D<au>,
    priv min_width_: au,
}

impl TextRun {
    fn size() -> Size2D<au> { self.size_ }
    fn preferred_width() -> au { self.size_.width }
    fn min_width() -> au { self.min_width_ }
}

fn TextRun(font: Font, text: ~str) -> TextRun {
    let glyphs = shape_text(&font, text);
    let size = glyph_run_size(glyphs);

    let min_width = match calc_min_width(&font, text) {
      Some(w) => w,
      None => size.width
    };

    TextRun {
        glyphs: shape_text(&font, text),
        size_: size,
        min_width_: min_width
    }
}

fn glyph_run_size(glyphs: &[Glyph]) -> Size2D<au> {
    let height = px_to_au(20);
    let pen_start_x = px_to_au(0);
    let pen_start_y = height;
    let pen_start = Point2D(pen_start_x, pen_start_y);
    let pen_end = glyphs.foldl(pen_start, |cur, glyph| {
        Point2D(cur.x.add(glyph.pos.offset.x).add(glyph.pos.advance.x),
                cur.y.add(glyph.pos.offset.y).add(glyph.pos.advance.y))
    });
    return Size2D(pen_end.x, pen_end.y);
}

/// If there are breaking opportunities inside a string, then
/// returns the width of the text up to the first break. Otherwise None.
fn calc_min_width(font: &Font, text: &str) -> Option<au> {
    match str::find(text, |c| char::is_whitespace(c)) {
      Some(offset) => {
        let short_text = str::view(text, 0, offset);
        let glyphs = shape_text(font, short_text);
        let size = glyph_run_size(glyphs);
        Some(size.width)
      }
      None => None
    }
}

#[test]
fn test_calc_min_width_with_breaking() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_width(font, ~"firecracker yumyum");
    let expected = Some(px_to_au(84));
    assert expected == actual;
}

#[test]
fn test_calc_min_width_without_breaking() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_width(font, ~"firecracker_yumyum");
    let expected = None;
    assert expected == actual;
}

fn should_calculate_the_total_size() {
    #[test];
    #[ignore(cfg(target_os = "macos"))];

    let flib = FontLibrary();
    let font = flib.get_test_font();
    let run = TextRun(*font, ~"firecracker");
    let expected = Size2D(px_to_au(84), px_to_au(20));
    assert run.size() == expected;
}

<commit_msg>That min_width calculation was totally wrong<commit_after>use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::{au, px_to_au};
use libc::{c_void};
use font_library::FontLibrary;
use font::Font;
use glyph::Glyph;
use shaper::shape_text;

#[doc="A single, unbroken line of text."]
struct TextRun {
    priv glyphs: ~[Glyph],
    priv size_: Size2D<au>,
    priv min_width_: au,
}

impl TextRun {
    fn size() -> Size2D<au> { self.size_ }
    fn preferred_width() -> au { self.size_.width }
    fn min_width() -> au { self.min_width_ }
}

fn TextRun(font: Font, text: ~str) -> TextRun {
    let glyphs = shape_text(&font, text);
    let size = glyph_run_size(glyphs);

    let min_width = match calc_min_width(&font, text) {
      Some(w) => w,
      None => size.width
    };

    TextRun {
        glyphs: shape_text(&font, text),
        size_: size,
        min_width_: min_width
    }
}

fn glyph_run_size(glyphs: &[Glyph]) -> Size2D<au> {
    let height = px_to_au(20);
    let pen_start_x = px_to_au(0);
    let pen_start_y = height;
    let pen_start = Point2D(pen_start_x, pen_start_y);
    let pen_end = glyphs.foldl(pen_start, |cur, glyph| {
        Point2D(cur.x.add(glyph.pos.offset.x).add(glyph.pos.advance.x),
                cur.y.add(glyph.pos.offset.y).add(glyph.pos.advance.y))
    });
    return Size2D(pen_end.x, pen_end.y);
}

/// If there are breaking opportunities inside a string, then
/// returns the width of the text up to the first break. Otherwise None.
fn calc_min_width(font: &Font, text: &str) -> Option<au> {
    None
}

#[test]
#[ignore]
fn test_calc_min_width_with_breaking() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_width(font, ~"firecracker yumyum");
    let expected = Some(px_to_au(84));
    assert expected == actual;
}

#[test]
fn test_calc_min_width_without_breaking() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_width(font, ~"firecracker_yumyum");
    let expected = None;
    assert expected == actual;
}

fn should_calculate_the_total_size() {
    #[test];
    #[ignore(cfg(target_os = "macos"))];

    let flib = FontLibrary();
    let font = flib.get_test_font();
    let run = TextRun(*font, ~"firecracker");
    let expected = Size2D(px_to_au(84), px_to_au(20));
    assert run.size() == expected;
}

<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::fmt;

use direction::Direction;
use platform;

#[derive(Debug)]
pub enum PrimaryCommand {
  Go(Direction),
  Inventory,
  Look,
  Quit,
}

pub enum Item {
  Torch,
}

impl fmt::Display for Item {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Item::Torch => "a torch",
    })
  }
}

pub enum InventoryCommand {
  Buy(Item, i32),
  Quit,
}

type HelpInfo = &'static [(char, &'static str)];

pub trait CommandProcessor<T> {
  fn from_char(c: char) -> Option<T>;

  fn get_help() -> HelpInfo;

  fn prompt() -> &'static str { "> " }

  fn show_help() {
    for &(ch, desc) in Self::get_help().iter() {
      println!("  {} - {}", ch, desc);
    }
  }

  fn get() -> Option<T> {
    platform::show_prompt(Self::prompt());

    match platform::read_input() {
      Some(input) => {
        platform::hide_prompt();
        match input.chars().next() {
          Some(k) => {
            let k = k.to_ascii_lowercase();
            if k == 'h' || k == '?' {
              println!("Here's what I understand right now:\n");
              Self::show_help();
              return None;
            } else if let Some(cmd) = Self::from_char(k) {
              return Some(cmd);
            }
          },
          None => {}
        }
        println!("I have no idea what you're talking about.");
        return None;
      },
      None => {
        return None;
      }
    }
  }
}

static PRIMARY_COMMAND_HELP: HelpInfo = &[
  ('n', "go north"),
  ('s', "go south"),
  ('e', "go east"),
  ('w', "go west"),
  ('u', "go up"),
  ('d', "go down"),
  ('i', "inventory/buy provisions"),
  ('l', "look around"),
  ('q', "quit"),
];

impl CommandProcessor<PrimaryCommand> for PrimaryCommand {
  fn get_help() -> HelpInfo { PRIMARY_COMMAND_HELP }

  fn from_char(c: char) -> Option<PrimaryCommand> {
    match c {
      'n' => { return Some(PrimaryCommand::Go(Direction::North)); },
      's' => { return Some(PrimaryCommand::Go(Direction::South)); },
      'e' => { return Some(PrimaryCommand::Go(Direction::East)); },
      'w' => { return Some(PrimaryCommand::Go(Direction::West)); },
      'u' => { return Some(PrimaryCommand::Go(Direction::Up)); },
      'd' => { return Some(PrimaryCommand::Go(Direction::Down)); },
      'i' => { return Some(PrimaryCommand::Inventory); },
      'l' => { return Some(PrimaryCommand::Look); },
      'q' => { return Some(PrimaryCommand::Quit); },
      _ => { return None; },
    }
  }
}

static INVENTORY_COMMAND_HELP: HelpInfo = &[
  ('1', "buy a flaming torch ($15)"),
  ('0', "continue adventure"),
];

impl CommandProcessor<InventoryCommand> for InventoryCommand {
  fn get_help() -> HelpInfo { INVENTORY_COMMAND_HELP }

  fn from_char(c: char) -> Option<InventoryCommand> {
    match c {
      '1' => Some(InventoryCommand::Buy(Item::Torch, 15)),
      _ => Some(InventoryCommand::Quit),
    }
  }
}
<commit_msg>Get rid of superfluous 'return' statements.<commit_after>use std::ascii::AsciiExt;
use std::fmt;

use direction::Direction;
use platform;

#[derive(Debug)]
pub enum PrimaryCommand {
  Go(Direction),
  Inventory,
  Look,
  Quit,
}

pub enum Item {
  Torch,
}

impl fmt::Display for Item {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Item::Torch => "a torch",
    })
  }
}

pub enum InventoryCommand {
  Buy(Item, i32),
  Quit,
}

type HelpInfo = &'static [(char, &'static str)];

pub trait CommandProcessor<T> {
  fn from_char(c: char) -> Option<T>;

  fn get_help() -> HelpInfo;

  fn prompt() -> &'static str { "> " }

  fn show_help() {
    for &(ch, desc) in Self::get_help().iter() {
      println!("  {} - {}", ch, desc);
    }
  }

  fn get() -> Option<T> {
    platform::show_prompt(Self::prompt());

    match platform::read_input() {
      Some(input) => {
        platform::hide_prompt();
        match input.chars().next() {
          Some(k) => {
            let k = k.to_ascii_lowercase();
            if k == 'h' || k == '?' {
              println!("Here's what I understand right now:\n");
              Self::show_help();
              return None;
            } else if let Some(cmd) = Self::from_char(k) {
              return Some(cmd);
            }
          },
          None => {}
        }
        println!("I have no idea what you're talking about.");
        return None;
      },
      None => {
        return None;
      }
    }
  }
}

static PRIMARY_COMMAND_HELP: HelpInfo = &[
  ('n', "go north"),
  ('s', "go south"),
  ('e', "go east"),
  ('w', "go west"),
  ('u', "go up"),
  ('d', "go down"),
  ('i', "inventory/buy provisions"),
  ('l', "look around"),
  ('q', "quit"),
];

impl CommandProcessor<PrimaryCommand> for PrimaryCommand {
  fn get_help() -> HelpInfo { PRIMARY_COMMAND_HELP }

  fn from_char(c: char) -> Option<PrimaryCommand> {
    match c {
      'n' => Some(PrimaryCommand::Go(Direction::North)),
      's' => Some(PrimaryCommand::Go(Direction::South)),
      'e' => Some(PrimaryCommand::Go(Direction::East)),
      'w' => Some(PrimaryCommand::Go(Direction::West)),
      'u' => Some(PrimaryCommand::Go(Direction::Up)),
      'd' => Some(PrimaryCommand::Go(Direction::Down)),
      'i' => Some(PrimaryCommand::Inventory),
      'l' => Some(PrimaryCommand::Look),
      'q' => Some(PrimaryCommand::Quit),
      _ => None,
    }
  }
}

static INVENTORY_COMMAND_HELP: HelpInfo = &[
  ('1', "buy a flaming torch ($15)"),
  ('0', "continue adventure"),
];

impl CommandProcessor<InventoryCommand> for InventoryCommand {
  fn get_help() -> HelpInfo { INVENTORY_COMMAND_HELP }

  fn from_char(c: char) -> Option<InventoryCommand> {
    match c {
      '1' => Some(InventoryCommand::Buy(Item::Torch, 15)),
      _ => Some(InventoryCommand::Quit),
    }
  }
}
<|endoftext|>


<commit_before>extern crate ndarray;

use ndarray::{
    RcArray,
    Array,
    RemoveAxis,
    arr2,
    Axis,
    Dimension,
    Dim,
};

#[test]
fn remove_axis()
{
    assert_eq!(Dim([3]).remove_axis(Axis(0)), Dim([]));
    assert_eq!(Dim([1, 2]).remove_axis(Axis(0)), Dim([2]));
    assert_eq!(Dim([4, 5, 6]).remove_axis(Axis(1)), Dim([4, 6]));

    assert_eq!(Dim(vec![1,2]).remove_axis(Axis(0)), Dim(vec![2]));
    assert_eq!(Dim(vec![4, 5, 6]).remove_axis(Axis(1)), Dim(vec![4, 6]));

    let a = RcArray::<f32, _>::zeros((4,5));
    a.subview(Axis(1), 0);

    /*
    let a = RcArray::<f32, _>::zeros(vec![4,5,6]);
    let _b = a.into_subview(Axis(1), 0).reshape((4, 6)).reshape(vec![2, 3, 4]);
    */

}

#[test]
fn dyn_dimension()
{
    let a = arr2(&[[1., 2.], [3., 4.0]]).into_shape(vec![2, 2]).unwrap();
    assert_eq!(&a - &a, Array::zeros(vec![2, 2]));
    assert_eq!(a[&[0, 0][..]], 1.);
    assert_eq!(a[vec![0, 0]], 1.);

    let mut dim = vec![1; 1024];
    dim[16] = 4;
    dim[17] = 3;
    let z = Array::<f32, _>::zeros(dim.clone());
    assert_eq!(z.shape(), &dim[..]);
}

#[test]
fn fastest_varying_order() {
    let strides = Dim([2, 8, 4, 1]);
    let order = strides._fastest_varying_stride_order();
    assert_eq!(order.slice(), &[3, 0, 2, 1]);

    assert_eq!(Dim([1, 3])._fastest_varying_stride_order(), Dim([0, 1]));
    assert_eq!(Dim([7, 2])._fastest_varying_stride_order(), Dim([1, 0]));
    assert_eq!(Dim([6, 1, 3])._fastest_varying_stride_order(), Dim([1, 2, 0]));

    // it's important that it produces distinct indices. Prefer the stable order
    // where 0 is before 1 when they are equal.
    assert_eq!(Dim([2, 2])._fastest_varying_stride_order(), [0, 1]);
    assert_eq!(Dim([2, 2, 1])._fastest_varying_stride_order(), [2, 0, 1]);
    assert_eq!(Dim([2, 2, 3, 1, 2])._fastest_varying_stride_order(), [3, 0, 1, 4, 2]);
}

#[test]
fn test_indexing() {
    let mut x = Dim([1, 2]);

    assert_eq!(x[0], 1);
    assert_eq!(x[1], 2);

    x[0] = 7;
    assert_eq!(x, [7, 2]);
}

#[test]
fn test_operations() {
    let mut x = Dim([1, 2]);
    let mut y = Dim([1, 1]);

    assert_eq!(x + y, [2, 3]);

    x += y;
    assert_eq!(x, [2, 3]);
    x *= 2;
    assert_eq!(x, [4, 6]);

    y -= 1;
    assert_eq!(y, [0, 0]);
}

#[test]
fn test_generic_operations() {
    fn test_dim<D: Dimension>(d: &D) {
        let mut x = d.clone();
        let mut v = x.as_array_view_mut();
        assert_eq!(v[0], 2);
        v += 1;
        assert_eq!(v[0], 3);
        v += &d.as_array_view();
        assert_eq!(v[0], 5);

        assert_eq!(v[..].len(), x.ndim());
        assert_eq!(&v[..], x.slice());
    }

    test_dim(&Dim([2, 3, 4]));
    test_dim(&Dim(vec![2, 3, 4, 1]));
    test_dim(&Dim(2));
}
<commit_msg>Update dimension tests<commit_after>extern crate ndarray;

use ndarray::{
    RcArray,
    Array,
    RemoveAxis,
    arr2,
    Axis,
    Dimension,
    Dim,
};

#[test]
fn remove_axis()
{
    assert_eq!(Dim([3]).remove_axis(Axis(0)), Dim([]));
    assert_eq!(Dim([1, 2]).remove_axis(Axis(0)), Dim([2]));
    assert_eq!(Dim([4, 5, 6]).remove_axis(Axis(1)), Dim([4, 6]));

    assert_eq!(Dim(vec![1,2]).remove_axis(Axis(0)), Dim(vec![2]));
    assert_eq!(Dim(vec![4, 5, 6]).remove_axis(Axis(1)), Dim(vec![4, 6]));

    let a = RcArray::<f32, _>::zeros((4,5));
    a.subview(Axis(1), 0);

    /*
    let a = RcArray::<f32, _>::zeros(vec![4,5,6]);
    let _b = a.into_subview(Axis(1), 0).reshape((4, 6)).reshape(vec![2, 3, 4]);
    */

}

#[test]
fn dyn_dimension()
{
    let a = arr2(&[[1., 2.], [3., 4.0]]).into_shape(vec![2, 2]).unwrap();
    assert_eq!(&a - &a, Array::zeros(vec![2, 2]));
    assert_eq!(a[&[0, 0][..]], 1.);
    assert_eq!(a[vec![0, 0]], 1.);

    let mut dim = vec![1; 1024];
    dim[16] = 4;
    dim[17] = 3;
    let z = Array::<f32, _>::zeros(dim.clone());
    assert_eq!(z.shape(), &dim[..]);
}

#[test]
fn fastest_varying_order() {
    let strides = Dim([2, 8, 4, 1]);
    let order = strides._fastest_varying_stride_order();
    assert_eq!(order.slice(), &[3, 0, 2, 1]);

    assert_eq!(Dim([1, 3])._fastest_varying_stride_order(), Dim([0, 1]));
    assert_eq!(Dim([7, 2])._fastest_varying_stride_order(), Dim([1, 0]));
    assert_eq!(Dim([6, 1, 3])._fastest_varying_stride_order(), Dim([1, 2, 0]));

    // it's important that it produces distinct indices. Prefer the stable order
    // where 0 is before 1 when they are equal.
    assert_eq!(Dim([2, 2])._fastest_varying_stride_order(), [0, 1]);
    assert_eq!(Dim([2, 2, 1])._fastest_varying_stride_order(), [2, 0, 1]);
    assert_eq!(Dim([2, 2, 3, 1, 2])._fastest_varying_stride_order(), [3, 0, 1, 4, 2]);
}

#[test]
fn test_indexing() {
    let mut x = Dim([1, 2]);

    assert_eq!(x[0], 1);
    assert_eq!(x[1], 2);

    x[0] = 7;
    assert_eq!(x, [7, 2]);
}

#[test]
fn test_operations() {
    let mut x = Dim([1, 2]);
    let mut y = Dim([1, 1]);

    assert_eq!(x + y, [2, 3]);

    x += y;
    assert_eq!(x, [2, 3]);
    x *= 2;
    assert_eq!(x, [4, 6]);

    y -= 1;
    assert_eq!(y, [0, 0]);
}

#[test]
fn test_generic_operations() {
    fn test_dim<D: Dimension>(d: &D) {
        let mut x = d.clone();
        x += 1;
        assert_eq!(x.as_array_view()[0], 3);
        x += d;
        assert_eq!(x.as_array_view()[0], 5);
    }

    test_dim(&Dim([2, 3, 4]));
    test_dim(&Dim(vec![2, 3, 4, 1]));
    test_dim(&Dim(2));
}
<|endoftext|>


<commit_before>#[cfg(windows)]
extern crate winapi;

extern crate libloading;
use libloading::{Symbol, Library};

const LIBPATH: &'static str = "target/libtest_helpers.module";

fn make_helpers() {
    static ONCE: ::std::sync::Once = ::std::sync::Once::new();
    ONCE.call_once(|| {
        let rustc = std::env::var_os("RUSTC").unwrap_or_else(|| { "rustc".into() });
        let mut cmd = ::std::process::Command::new(rustc);
        cmd
            .arg("src/test_helpers.rs")
            .arg("-o")
            .arg(LIBPATH)
            // .arg("--target")
            // .arg(env!("LIBLOADING_TEST_TARGET"))
            .arg("-O");

        cmd
            .output()
            .expect("could not compile the test helpers!");
    });
}

#[test]
fn test_id_u32() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        let f: Symbol<unsafe extern fn(u32) -> u32> = lib.get(b"test_identity_u32\0").unwrap();
        assert_eq!(42, f(42));
    }
}

#[repr(C)]
#[derive(Clone,Copy,PartialEq,Debug)]
struct S {
    a: u64,
    b: u32,
    c: u16,
    d: u8
}

#[test]
fn test_id_struct() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        let f: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
        assert_eq!(S { a: 1, b: 2, c: 3, d: 4 }, f(S { a: 1, b: 2, c: 3, d: 4 }));
    }
}

#[test]
fn test_0_no_0() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        let f: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
        let f2: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct").unwrap();
        assert_eq!(*f, *f2);
    }
}

#[test]
fn wrong_name_fails() {
    Library::new("target/this_location_is_definitely_non existent:^~").err().unwrap();
}

#[test]
fn missing_symbol_fails() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        lib.get::<*mut ()>(b"test_does_not_exist").err().unwrap();
        lib.get::<*mut ()>(b"test_does_not_exist\0").err().unwrap();
    }
}

#[test]
fn interior_null_fails() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        lib.get::<*mut ()>(b"test_does\0_not_exist").err().unwrap();
        lib.get::<*mut ()>(b"test\0_does_not_exist\0").err().unwrap();
    }
}

#[test]
fn test_incompatible_type() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        assert!(match lib.get::<()>(b"test_identity_u32\0") {
           Err(libloading::Error::IncompatibleSize) => true,
           _ => false,
        })
    }
}

#[test]
fn test_incompatible_type_named_fn() {
    make_helpers();
    unsafe fn get<'a, T>(l: &'a Library, _: T) -> Result<Symbol<'a, T>, libloading::Error> {
        l.get::<T>(b"test_identity_u32\0")
    }
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        assert!(match get(&lib, test_incompatible_type_named_fn) {
           Err(libloading::Error::IncompatibleSize) => true,
           _ => false,
        })
    }
}

#[test]
fn test_static_u32() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        let var: Symbol<*mut u32> = lib.get(b"TEST_STATIC_U32\0").unwrap();
        **var = 42;
        let help: Symbol<unsafe extern fn() -> u32> = lib.get(b"test_get_static_u32\0").unwrap();
        assert_eq!(42, help());
    }
}

#[test]
fn test_static_ptr() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        let var: Symbol<*mut *mut ()> = lib.get(b"TEST_STATIC_PTR\0").unwrap();
        **var = *var as *mut _;
        let works: Symbol<unsafe extern fn() -> bool> =
            lib.get(b"test_check_static_ptr\0").unwrap();
        assert!(works());
    }
}

#[cfg(unix)]
#[test]
fn library_this_get() {
    use libloading::os::unix::Library;
    make_helpers();
    let _lib = Library::new(LIBPATH).unwrap();
    let this = Library::this();
    // SAFE: functions are never called
    unsafe {
        // Library we loaded in `_lib` (should be RTLD_LOCAL).
        // FIXME: inconsistent behaviour between macos and other posix systems
        // assert!(this.get::<unsafe extern "C" fn()>(b"test_identity_u32").is_err());
        // Something obscure from libc...
        assert!(this.get::<unsafe extern "C" fn()>(b"freopen").is_ok());
    }
}

#[cfg(windows)]
#[test]
fn library_this() {
    use libloading::os::windows::Library;
    make_helpers();
    let _lib = Library::new(LIBPATH).unwrap();
    let this = Library::this().expect("this library");
    // SAFE: functions are never called
    unsafe {
        // Library we loaded in `_lib`.
        assert!(this.get::<unsafe extern "C" fn()>(b"test_identity_u32").is_err());
        // Something "obscure" from kernel32...
        assert!(this.get::<unsafe extern "C" fn()>(b"GetLastError").is_err());
    }
}

#[cfg(windows)]
#[test]
fn works_getlasterror() {
    use winapi::um::errhandlingapi;
    use winapi::shared::minwindef::DWORD;
    use libloading::os::windows::{Library, Symbol};

    let lib = Library::new("kernel32.dll").unwrap();
    let gle: Symbol<unsafe extern "system" fn() -> DWORD> = unsafe {
        lib.get(b"GetLastError").unwrap()
    };
    unsafe {
        errhandlingapi::SetLastError(42);
        assert_eq!(errhandlingapi::GetLastError(), gle())
    }
}

#[cfg(windows)]
#[test]
fn works_getlasterror0() {
    use winapi::um::errhandlingapi;
    use winapi::shared::minwindef::DWORD;
    use libloading::os::windows::{Library, Symbol};

    let lib = Library::new("kernel32.dll").unwrap();
    let gle: Symbol<unsafe extern "system" fn() -> DWORD> = unsafe {
        lib.get(b"GetLastError\0").unwrap()
    };
    unsafe {
        errhandlingapi::SetLastError(42);
        assert_eq!(errhandlingapi::GetLastError(), gle())
    }
}
<commit_msg>Tests read TARGET environment variable for helpers<commit_after>#[cfg(windows)]
extern crate winapi;

extern crate libloading;
use libloading::{Symbol, Library};

const LIBPATH: &'static str = "target/libtest_helpers.module";

fn make_helpers() {
    static ONCE: ::std::sync::Once = ::std::sync::Once::new();
    ONCE.call_once(|| {
        let rustc = std::env::var_os("RUSTC").unwrap_or_else(|| { "rustc".into() });
        let mut cmd = ::std::process::Command::new(rustc);
        cmd
            .arg("src/test_helpers.rs")
            .arg("-o")
            .arg(LIBPATH);
        if let Some(target) = std::env::var_os("TARGET") {
            cmd.arg("--target").arg(target);
        } else {
            eprintln!("WARNING: $TARGET NOT SPECIFIED! BUILDING HELPER MODULE FOR NATIVE TARGET.");
        }
        assert!(cmd
            .status()
            .expect("could not compile the test helpers!")
            .success()
        );
    });
}

#[test]
fn test_id_u32() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        let f: Symbol<unsafe extern fn(u32) -> u32> = lib.get(b"test_identity_u32\0").unwrap();
        assert_eq!(42, f(42));
    }
}

#[repr(C)]
#[derive(Clone,Copy,PartialEq,Debug)]
struct S {
    a: u64,
    b: u32,
    c: u16,
    d: u8
}

#[test]
fn test_id_struct() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        let f: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
        assert_eq!(S { a: 1, b: 2, c: 3, d: 4 }, f(S { a: 1, b: 2, c: 3, d: 4 }));
    }
}

#[test]
fn test_0_no_0() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        let f: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
        let f2: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct").unwrap();
        assert_eq!(*f, *f2);
    }
}

#[test]
fn wrong_name_fails() {
    Library::new("target/this_location_is_definitely_non existent:^~").err().unwrap();
}

#[test]
fn missing_symbol_fails() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        lib.get::<*mut ()>(b"test_does_not_exist").err().unwrap();
        lib.get::<*mut ()>(b"test_does_not_exist\0").err().unwrap();
    }
}

#[test]
fn interior_null_fails() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        lib.get::<*mut ()>(b"test_does\0_not_exist").err().unwrap();
        lib.get::<*mut ()>(b"test\0_does_not_exist\0").err().unwrap();
    }
}

#[test]
fn test_incompatible_type() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        assert!(match lib.get::<()>(b"test_identity_u32\0") {
           Err(libloading::Error::IncompatibleSize) => true,
           _ => false,
        })
    }
}

#[test]
fn test_incompatible_type_named_fn() {
    make_helpers();
    unsafe fn get<'a, T>(l: &'a Library, _: T) -> Result<Symbol<'a, T>, libloading::Error> {
        l.get::<T>(b"test_identity_u32\0")
    }
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        assert!(match get(&lib, test_incompatible_type_named_fn) {
           Err(libloading::Error::IncompatibleSize) => true,
           _ => false,
        })
    }
}

#[test]
fn test_static_u32() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        let var: Symbol<*mut u32> = lib.get(b"TEST_STATIC_U32\0").unwrap();
        **var = 42;
        let help: Symbol<unsafe extern fn() -> u32> = lib.get(b"test_get_static_u32\0").unwrap();
        assert_eq!(42, help());
    }
}

#[test]
fn test_static_ptr() {
    make_helpers();
    let lib = Library::new(LIBPATH).unwrap();
    unsafe {
        let var: Symbol<*mut *mut ()> = lib.get(b"TEST_STATIC_PTR\0").unwrap();
        **var = *var as *mut _;
        let works: Symbol<unsafe extern fn() -> bool> =
            lib.get(b"test_check_static_ptr\0").unwrap();
        assert!(works());
    }
}

#[cfg(unix)]
#[test]
fn library_this_get() {
    use libloading::os::unix::Library;
    make_helpers();
    let _lib = Library::new(LIBPATH).unwrap();
    let this = Library::this();
    // SAFE: functions are never called
    unsafe {
        // Library we loaded in `_lib` (should be RTLD_LOCAL).
        // FIXME: inconsistent behaviour between macos and other posix systems
        // assert!(this.get::<unsafe extern "C" fn()>(b"test_identity_u32").is_err());
        // Something obscure from libc...
        assert!(this.get::<unsafe extern "C" fn()>(b"freopen").is_ok());
    }
}

#[cfg(windows)]
#[test]
fn library_this() {
    use libloading::os::windows::Library;
    make_helpers();
    let _lib = Library::new(LIBPATH).unwrap();
    let this = Library::this().expect("this library");
    // SAFE: functions are never called
    unsafe {
        // Library we loaded in `_lib`.
        assert!(this.get::<unsafe extern "C" fn()>(b"test_identity_u32").is_err());
        // Something "obscure" from kernel32...
        assert!(this.get::<unsafe extern "C" fn()>(b"GetLastError").is_err());
    }
}

#[cfg(windows)]
#[test]
fn works_getlasterror() {
    use winapi::um::errhandlingapi;
    use winapi::shared::minwindef::DWORD;
    use libloading::os::windows::{Library, Symbol};

    let lib = Library::new("kernel32.dll").unwrap();
    let gle: Symbol<unsafe extern "system" fn() -> DWORD> = unsafe {
        lib.get(b"GetLastError").unwrap()
    };
    unsafe {
        errhandlingapi::SetLastError(42);
        assert_eq!(errhandlingapi::GetLastError(), gle())
    }
}

#[cfg(windows)]
#[test]
fn works_getlasterror0() {
    use winapi::um::errhandlingapi;
    use winapi::shared::minwindef::DWORD;
    use libloading::os::windows::{Library, Symbol};

    let lib = Library::new("kernel32.dll").unwrap();
    let gle: Symbol<unsafe extern "system" fn() -> DWORD> = unsafe {
        lib.get(b"GetLastError\0").unwrap()
    };
    unsafe {
        errhandlingapi::SetLastError(42);
        assert_eq!(errhandlingapi::GetLastError(), gle())
    }
}
<|endoftext|>