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

use std::collections::HashMap;
use std::path::Path;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TryRecvError};
use std::thread;
use std::time::Duration;

use butterfly;
use common::ui::UI;
use depot_client;
use env;
use hcore::package::{PackageIdent, PackageInstall};
use hcore::service::ServiceGroup;
use hcore::crypto::default_cache_key_path;
use hcore::fs::{CACHE_ARTIFACT_PATH, FS_ROOT_PATH};
use launcher_client::LauncherCli;
use time::{SteadyTime, Duration as TimeDuration};

use {PRODUCT, VERSION};
use error::Result;
use census::CensusRing;
use manager::service::{Service, Topology, UpdateStrategy};

static LOGKEY: &'static str = "SU";
const FREQUENCY_ENVVAR: &'static str = "HAB_UPDATE_STRATEGY_FREQUENCY_MS";
const DEFAULT_FREQUENCY: i64 = 60_000;

type UpdaterStateList = HashMap<ServiceGroup, UpdaterState>;

enum UpdaterState {
    AtOnce(Receiver<PackageInstall>),
    Rolling(RollingState),
}

enum RollingState {
    AwaitingElection,
    InElection,
    Leader(LeaderState),
    Follower(FollowerState),
}

enum LeaderState {
    Polling(Receiver<PackageInstall>),
    Waiting,
}

enum FollowerState {
    Waiting,
    Updating(Receiver<PackageInstall>),
}

pub struct ServiceUpdater {
    states: UpdaterStateList,
    butterfly: butterfly::Server,
}

impl ServiceUpdater {
    pub fn new(butterfly: butterfly::Server) -> Self {
        ServiceUpdater {
            states: UpdaterStateList::default(),
            butterfly: butterfly,
        }
    }

    pub fn add(&mut self, service: &Service) -> bool {
        match service.update_strategy {
            UpdateStrategy::None => false,
            UpdateStrategy::AtOnce => {
                self.states
                    .entry(service.service_group.clone())
                    .or_insert_with(|| {
                        let rx = Worker::new(service).start(&service.service_group, None);
                        UpdaterState::AtOnce(rx)
                    });
                true
            }
            UpdateStrategy::Rolling => {
                self.states.entry(service.service_group.clone()).or_insert(
                    UpdaterState::Rolling(RollingState::AwaitingElection),
                );
                true
            }
        }
    }

    pub fn check_for_updated_package(
        &mut self,
        service: &mut Service,
        census_ring: &CensusRing,
        launcher: &LauncherCli,
    ) -> bool {
        let mut updated = false;
        match self.states.get_mut(&service.service_group) {
            Some(&mut UpdaterState::AtOnce(ref mut rx)) => {
                match rx.try_recv() {
                    Ok(package) => {
                        service.update_package(package, launcher);
                        return true;
                    }
                    Err(TryRecvError::Empty) => return false,
                    Err(TryRecvError::Disconnected) => {}
                }
                debug!("Service Updater worker has died; restarting...");
                *rx = Worker::new(service).start(&service.service_group, None);
            }
            Some(&mut UpdaterState::Rolling(ref mut st @ RollingState::AwaitingElection)) => {
                if let Some(census_group) = census_ring.census_group_for(&service.service_group) {
                    if service.topology == Topology::Leader {
                        debug!(
                            "Rolling Update, determining proper suitability because we're in \
                                a leader topology"
                        );
                        match (census_group.me(), census_group.leader()) {
                            (Some(me), Some(leader)) => {
                                let suitability = if me.member_id == leader.member_id {
                                    u64::min_value()
                                } else {
                                    u64::max_value()
                                };
                                self.butterfly.start_update_election(
                                    service.service_group.clone(),
                                    suitability,
                                    0,
                                );
                                *st = RollingState::InElection
                            }
                            _ => return false,
                        }
                    } else {
                        debug!("Rolling update, using default suitability");
                        self.butterfly.start_update_election(
                            service.service_group.clone(),
                            0,
                            0,
                        );
                        *st = RollingState::InElection;
                    }
                }
            }
            Some(&mut UpdaterState::Rolling(ref mut st @ RollingState::InElection)) => {
                if let Some(census_group) = census_ring.census_group_for(&service.service_group) {
                    match (census_group.me(), census_group.update_leader()) {
                        (Some(me), Some(leader)) => {
                            if me.member_id == leader.member_id {
                                debug!("We're the leader");
                                // Start in waiting state to ensure all members agree with our
                                // version before attempting a new rolling upgrade.
                                *st = RollingState::Leader(LeaderState::Waiting);
                            } else {
                                debug!("We're a follower");
                                *st = RollingState::Follower(FollowerState::Waiting);
                            }
                        }
                        (Some(_), None) => return false,
                        _ => return false,
                    }
                }
            }
            Some(&mut UpdaterState::Rolling(RollingState::Leader(ref mut state))) => {
                match *state {
                    LeaderState::Polling(ref mut rx) => {
                        match rx.try_recv() {
                            Ok(package) => {
                                debug!("Rolling Update, polling found a new package");
                                service.update_package(package, launcher);
                                updated = true;
                            }
                            Err(TryRecvError::Empty) => return false,
                            Err(TryRecvError::Disconnected) => {
                                debug!("Service Updater worker has died; restarting...");
                                *rx = Worker::new(service).start(&service.service_group, None);
                            }
                        }
                    }
                    LeaderState::Waiting => {
                        match census_ring.census_group_for(&service.service_group) {
                            Some(census_group) => {
                                if census_group.members().iter().any(|cm| {
                                    cm.pkg.as_ref().unwrap() !=
                                        census_group.me().unwrap().pkg.as_ref().unwrap()
                                })
                                {
                                    debug!("Update leader still waiting for followers...");
                                    return false;
                                }
                                let rx = Worker::new(service).start(&service.service_group, None);
                                *state = LeaderState::Polling(rx);
                            }
                            None => {
                                panic!(
                                    "Expected census list to have service group '{}'!",
                                    &*service.service_group
                                )
                            }
                        }
                    }
                }
                if updated {
                    *state = LeaderState::Waiting;
                }
            }
            Some(&mut UpdaterState::Rolling(RollingState::Follower(ref mut state))) => {
                match *state {
                    FollowerState::Waiting => {
                        match census_ring.census_group_for(&service.service_group) {
                            Some(census_group) => {
                                match (
                                    census_group.update_leader(),
                                    census_group.previous_peer(),
                                    census_group.me(),
                                ) {
                                    (Some(leader), Some(peer), Some(me)) => {
                                        if leader.pkg == me.pkg {
                                            debug!("We're not in an update");
                                            return false;
                                        }
                                        if leader.pkg != peer.pkg {
                                            debug!("We're in an update but it's not our turn");
                                            return false;
                                        }
                                        debug!("We're in an update and it's our turn");
                                        let rx = Worker::new(service).start(
                                            &service.service_group,
                                            leader.pkg.clone(),
                                        );
                                        *state = FollowerState::Updating(rx);
                                    }
                                    _ => return false,
                                }
                            }
                            None => {
                                panic!(
                                    "Expected census list to have service group '{}'!",
                                    &*service.service_group
                                )
                            }
                        }
                    }
                    FollowerState::Updating(ref mut rx) => {
                        match census_ring.census_group_for(&service.service_group) {
                            Some(census_group) => {
                                match rx.try_recv() {
                                    Ok(package) => {
                                        service.update_package(package, launcher);
                                        updated = true
                                    }
                                    Err(TryRecvError::Empty) => return false,
                                    Err(TryRecvError::Disconnected) => {
                                        debug!("Service Updater worker has died; restarting...");
                                        let package =
                                            census_group.update_leader().unwrap().pkg.clone();
                                        *rx = Worker::new(service).start(
                                            &service.service_group,
                                            package,
                                        );
                                    }
                                }
                            }
                            None => {
                                panic!(
                                    "Expected census list to have service group '{}'!",
                                    &*service.service_group
                                )
                            }
                        }
                    }
                }
                if updated {
                    *state = FollowerState::Waiting;
                }
            }
            None => {}
        }
        updated
    }
}

struct Worker {
    current: PackageIdent,
    spec_ident: PackageIdent,
    depot: depot_client::Client,
    channel: String,
    update_strategy: UpdateStrategy,
    ui: UI,
}

impl Worker {
    fn new(service: &Service) -> Self {
        Worker {
            current: service.pkg.ident.clone(),
            spec_ident: service.spec_ident.clone(),
            depot: depot_client::Client::new(&service.depot_url, PRODUCT, VERSION, None).unwrap(),
            channel: service.channel.clone(),
            update_strategy: service.update_strategy.clone(),
            ui: UI::default(),
        }
    }

    /// Start a new update worker.
    ///
    /// Passing an optional package identifier will make the worker perform a run-once update to
    /// retrieve a specific version from a remote Depot. If no package identifier is specified,
    /// then the updater will poll until a newer more suitable package is found.
    fn start(mut self, sg: &ServiceGroup, ident: Option<PackageIdent>) -> Receiver<PackageInstall> {
        let (tx, rx) = sync_channel(0);
        thread::Builder::new()
            .name(format!("service-updater-{}", sg))
            .spawn(move || match ident {
                Some(latest) => self.run_once(tx, latest),
                None => self.run_poll(tx),
            })
            .expect("unable to start service-updater thread");
        rx
    }

    fn run_once(&mut self, sender: SyncSender<PackageInstall>, ident: PackageIdent) {
        outputln!("Updating from {} to {}", self.current, ident);
        loop {
            let next_check = SteadyTime::now() +
                TimeDuration::milliseconds(self.update_frequency());
            match self.install(&ident, true) {
                Ok(package) => {
                    self.current = package.ident().clone();
                    sender.send(package).expect("Main thread has gone away!");
                    break;
                }
                Err(e) => warn!("Failed to install updated package: {:?}", e),
            }
            let time_to_wait = (next_check - SteadyTime::now()).num_milliseconds();
            if time_to_wait > 0 {
                thread::sleep(Duration::from_millis(time_to_wait as u64));
            }
        }
    }

    fn run_poll(&mut self, sender: SyncSender<PackageInstall>) {
        loop {
            let next_check = SteadyTime::now() +
                TimeDuration::milliseconds(self.update_frequency());
            let mut package: Option<PackageInstall> = None;
            match self.depot.show_package(
                &self.spec_ident,
                Some(&self.channel),
            ) {
                Ok(remote) => {
                    let latest: PackageIdent = remote.get_ident().clone().into();
                    if latest > self.current {
                        outputln!("Updating from {} to {}", self.current, latest);
                        match self.install(&latest, true) {
                            Ok(pkg) => package = Some(pkg),
                            Err(e) => warn!("Failed to install updated package: {:?}", e),
                        }
                    } else {
                        info!("Package found is not newer than ours");
                    }
                }
                Err(e) => warn!("Updater failed to get latest package: {:?}", e),
            }
            if self.update_strategy == UpdateStrategy::AtOnce {
                if let Ok(cached) = PackageInstall::load(
                    &self.spec_ident,
                    Some(&Path::new(&*FS_ROOT_PATH)),
                )
                {
                    let compare = match package {
                        Some(ref pkg) => pkg.ident.clone(),
                        None => self.current.clone(),
                    };

                    if cached.ident > compare {
                        package = Some(cached);
                    }
                }
            }

            if let Some(pkg) = package {
                self.current = pkg.ident.clone();
                sender.send(pkg).expect("Main thread has gone away!");
                break;
            }
            let time_to_wait = (next_check - SteadyTime::now()).num_milliseconds();
            if time_to_wait > 0 {
                thread::sleep(Duration::from_millis(time_to_wait as u64));
            }
        }
    }

    fn install(&mut self, package: &PackageIdent, recurse: bool) -> Result<PackageInstall> {
        let package = match PackageInstall::load(package, Some(&*FS_ROOT_PATH)) {
            Ok(pkg) => pkg,
            Err(_) => self.download(package)?,
        };
        if recurse {
            for ident in package.tdeps()?.iter() {
                self.install(&ident, false)?;
            }
        }
        Ok(package)
    }

    fn download(&mut self, package: &PackageIdent) -> Result<PackageInstall> {
        outputln!("Downloading {}", package);
        let mut archive = self.depot.fetch_package(
            package,
            &Path::new(&*FS_ROOT_PATH).join(
                CACHE_ARTIFACT_PATH,
            ),
            self.ui.progress(),
        )?;
        archive.verify(&default_cache_key_path(None))?;
        outputln!("Installing {}", package);
        archive.unpack(None)?;
        let pkg = PackageInstall::load(archive.ident().as_ref().unwrap(), Some(&*FS_ROOT_PATH))?;
        Ok(pkg)
    }

    fn update_frequency(&self) -> i64 {
        match env::var(FREQUENCY_ENVVAR) {
            Ok(val) => {
                match val.parse::<i64>() {
                    Ok(num) => num,
                    Err(_) => {
                        outputln!(
                            "Unable to parse '{}' from {} as a valid integer. Falling back \
                                  to defailt {} MS frequency.",
                            val,
                            FREQUENCY_ENVVAR,
                            DEFAULT_FREQUENCY
                        );
                        DEFAULT_FREQUENCY
                    }
                }
            }
            Err(_) => DEFAULT_FREQUENCY,
        }
    }
}
<commit_msg>Fix spelling error<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashMap;
use std::path::Path;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TryRecvError};
use std::thread;
use std::time::Duration;

use butterfly;
use common::ui::UI;
use depot_client;
use env;
use hcore::package::{PackageIdent, PackageInstall};
use hcore::service::ServiceGroup;
use hcore::crypto::default_cache_key_path;
use hcore::fs::{CACHE_ARTIFACT_PATH, FS_ROOT_PATH};
use launcher_client::LauncherCli;
use time::{SteadyTime, Duration as TimeDuration};

use {PRODUCT, VERSION};
use error::Result;
use census::CensusRing;
use manager::service::{Service, Topology, UpdateStrategy};

static LOGKEY: &'static str = "SU";
const FREQUENCY_ENVVAR: &'static str = "HAB_UPDATE_STRATEGY_FREQUENCY_MS";
const DEFAULT_FREQUENCY: i64 = 60_000;

type UpdaterStateList = HashMap<ServiceGroup, UpdaterState>;

enum UpdaterState {
    AtOnce(Receiver<PackageInstall>),
    Rolling(RollingState),
}

enum RollingState {
    AwaitingElection,
    InElection,
    Leader(LeaderState),
    Follower(FollowerState),
}

enum LeaderState {
    Polling(Receiver<PackageInstall>),
    Waiting,
}

enum FollowerState {
    Waiting,
    Updating(Receiver<PackageInstall>),
}

pub struct ServiceUpdater {
    states: UpdaterStateList,
    butterfly: butterfly::Server,
}

impl ServiceUpdater {
    pub fn new(butterfly: butterfly::Server) -> Self {
        ServiceUpdater {
            states: UpdaterStateList::default(),
            butterfly: butterfly,
        }
    }

    pub fn add(&mut self, service: &Service) -> bool {
        match service.update_strategy {
            UpdateStrategy::None => false,
            UpdateStrategy::AtOnce => {
                self.states
                    .entry(service.service_group.clone())
                    .or_insert_with(|| {
                        let rx = Worker::new(service).start(&service.service_group, None);
                        UpdaterState::AtOnce(rx)
                    });
                true
            }
            UpdateStrategy::Rolling => {
                self.states.entry(service.service_group.clone()).or_insert(
                    UpdaterState::Rolling(RollingState::AwaitingElection),
                );
                true
            }
        }
    }

    pub fn check_for_updated_package(
        &mut self,
        service: &mut Service,
        census_ring: &CensusRing,
        launcher: &LauncherCli,
    ) -> bool {
        let mut updated = false;
        match self.states.get_mut(&service.service_group) {
            Some(&mut UpdaterState::AtOnce(ref mut rx)) => {
                match rx.try_recv() {
                    Ok(package) => {
                        service.update_package(package, launcher);
                        return true;
                    }
                    Err(TryRecvError::Empty) => return false,
                    Err(TryRecvError::Disconnected) => {}
                }
                debug!("Service Updater worker has died; restarting...");
                *rx = Worker::new(service).start(&service.service_group, None);
            }
            Some(&mut UpdaterState::Rolling(ref mut st @ RollingState::AwaitingElection)) => {
                if let Some(census_group) = census_ring.census_group_for(&service.service_group) {
                    if service.topology == Topology::Leader {
                        debug!(
                            "Rolling Update, determining proper suitability because we're in \
                                a leader topology"
                        );
                        match (census_group.me(), census_group.leader()) {
                            (Some(me), Some(leader)) => {
                                let suitability = if me.member_id == leader.member_id {
                                    u64::min_value()
                                } else {
                                    u64::max_value()
                                };
                                self.butterfly.start_update_election(
                                    service.service_group.clone(),
                                    suitability,
                                    0,
                                );
                                *st = RollingState::InElection
                            }
                            _ => return false,
                        }
                    } else {
                        debug!("Rolling update, using default suitability");
                        self.butterfly.start_update_election(
                            service.service_group.clone(),
                            0,
                            0,
                        );
                        *st = RollingState::InElection;
                    }
                }
            }
            Some(&mut UpdaterState::Rolling(ref mut st @ RollingState::InElection)) => {
                if let Some(census_group) = census_ring.census_group_for(&service.service_group) {
                    match (census_group.me(), census_group.update_leader()) {
                        (Some(me), Some(leader)) => {
                            if me.member_id == leader.member_id {
                                debug!("We're the leader");
                                // Start in waiting state to ensure all members agree with our
                                // version before attempting a new rolling upgrade.
                                *st = RollingState::Leader(LeaderState::Waiting);
                            } else {
                                debug!("We're a follower");
                                *st = RollingState::Follower(FollowerState::Waiting);
                            }
                        }
                        (Some(_), None) => return false,
                        _ => return false,
                    }
                }
            }
            Some(&mut UpdaterState::Rolling(RollingState::Leader(ref mut state))) => {
                match *state {
                    LeaderState::Polling(ref mut rx) => {
                        match rx.try_recv() {
                            Ok(package) => {
                                debug!("Rolling Update, polling found a new package");
                                service.update_package(package, launcher);
                                updated = true;
                            }
                            Err(TryRecvError::Empty) => return false,
                            Err(TryRecvError::Disconnected) => {
                                debug!("Service Updater worker has died; restarting...");
                                *rx = Worker::new(service).start(&service.service_group, None);
                            }
                        }
                    }
                    LeaderState::Waiting => {
                        match census_ring.census_group_for(&service.service_group) {
                            Some(census_group) => {
                                if census_group.members().iter().any(|cm| {
                                    cm.pkg.as_ref().unwrap() !=
                                        census_group.me().unwrap().pkg.as_ref().unwrap()
                                })
                                {
                                    debug!("Update leader still waiting for followers...");
                                    return false;
                                }
                                let rx = Worker::new(service).start(&service.service_group, None);
                                *state = LeaderState::Polling(rx);
                            }
                            None => {
                                panic!(
                                    "Expected census list to have service group '{}'!",
                                    &*service.service_group
                                )
                            }
                        }
                    }
                }
                if updated {
                    *state = LeaderState::Waiting;
                }
            }
            Some(&mut UpdaterState::Rolling(RollingState::Follower(ref mut state))) => {
                match *state {
                    FollowerState::Waiting => {
                        match census_ring.census_group_for(&service.service_group) {
                            Some(census_group) => {
                                match (
                                    census_group.update_leader(),
                                    census_group.previous_peer(),
                                    census_group.me(),
                                ) {
                                    (Some(leader), Some(peer), Some(me)) => {
                                        if leader.pkg == me.pkg {
                                            debug!("We're not in an update");
                                            return false;
                                        }
                                        if leader.pkg != peer.pkg {
                                            debug!("We're in an update but it's not our turn");
                                            return false;
                                        }
                                        debug!("We're in an update and it's our turn");
                                        let rx = Worker::new(service).start(
                                            &service.service_group,
                                            leader.pkg.clone(),
                                        );
                                        *state = FollowerState::Updating(rx);
                                    }
                                    _ => return false,
                                }
                            }
                            None => {
                                panic!(
                                    "Expected census list to have service group '{}'!",
                                    &*service.service_group
                                )
                            }
                        }
                    }
                    FollowerState::Updating(ref mut rx) => {
                        match census_ring.census_group_for(&service.service_group) {
                            Some(census_group) => {
                                match rx.try_recv() {
                                    Ok(package) => {
                                        service.update_package(package, launcher);
                                        updated = true
                                    }
                                    Err(TryRecvError::Empty) => return false,
                                    Err(TryRecvError::Disconnected) => {
                                        debug!("Service Updater worker has died; restarting...");
                                        let package =
                                            census_group.update_leader().unwrap().pkg.clone();
                                        *rx = Worker::new(service).start(
                                            &service.service_group,
                                            package,
                                        );
                                    }
                                }
                            }
                            None => {
                                panic!(
                                    "Expected census list to have service group '{}'!",
                                    &*service.service_group
                                )
                            }
                        }
                    }
                }
                if updated {
                    *state = FollowerState::Waiting;
                }
            }
            None => {}
        }
        updated
    }
}

struct Worker {
    current: PackageIdent,
    spec_ident: PackageIdent,
    depot: depot_client::Client,
    channel: String,
    update_strategy: UpdateStrategy,
    ui: UI,
}

impl Worker {
    fn new(service: &Service) -> Self {
        Worker {
            current: service.pkg.ident.clone(),
            spec_ident: service.spec_ident.clone(),
            depot: depot_client::Client::new(&service.depot_url, PRODUCT, VERSION, None).unwrap(),
            channel: service.channel.clone(),
            update_strategy: service.update_strategy.clone(),
            ui: UI::default(),
        }
    }

    /// Start a new update worker.
    ///
    /// Passing an optional package identifier will make the worker perform a run-once update to
    /// retrieve a specific version from a remote Depot. If no package identifier is specified,
    /// then the updater will poll until a newer more suitable package is found.
    fn start(mut self, sg: &ServiceGroup, ident: Option<PackageIdent>) -> Receiver<PackageInstall> {
        let (tx, rx) = sync_channel(0);
        thread::Builder::new()
            .name(format!("service-updater-{}", sg))
            .spawn(move || match ident {
                Some(latest) => self.run_once(tx, latest),
                None => self.run_poll(tx),
            })
            .expect("unable to start service-updater thread");
        rx
    }

    fn run_once(&mut self, sender: SyncSender<PackageInstall>, ident: PackageIdent) {
        outputln!("Updating from {} to {}", self.current, ident);
        loop {
            let next_check = SteadyTime::now() +
                TimeDuration::milliseconds(self.update_frequency());
            match self.install(&ident, true) {
                Ok(package) => {
                    self.current = package.ident().clone();
                    sender.send(package).expect("Main thread has gone away!");
                    break;
                }
                Err(e) => warn!("Failed to install updated package: {:?}", e),
            }
            let time_to_wait = (next_check - SteadyTime::now()).num_milliseconds();
            if time_to_wait > 0 {
                thread::sleep(Duration::from_millis(time_to_wait as u64));
            }
        }
    }

    fn run_poll(&mut self, sender: SyncSender<PackageInstall>) {
        loop {
            let next_check = SteadyTime::now() +
                TimeDuration::milliseconds(self.update_frequency());
            let mut package: Option<PackageInstall> = None;
            match self.depot.show_package(
                &self.spec_ident,
                Some(&self.channel),
            ) {
                Ok(remote) => {
                    let latest: PackageIdent = remote.get_ident().clone().into();
                    if latest > self.current {
                        outputln!("Updating from {} to {}", self.current, latest);
                        match self.install(&latest, true) {
                            Ok(pkg) => package = Some(pkg),
                            Err(e) => warn!("Failed to install updated package: {:?}", e),
                        }
                    } else {
                        info!("Package found is not newer than ours");
                    }
                }
                Err(e) => warn!("Updater failed to get latest package: {:?}", e),
            }
            if self.update_strategy == UpdateStrategy::AtOnce {
                if let Ok(cached) = PackageInstall::load(
                    &self.spec_ident,
                    Some(&Path::new(&*FS_ROOT_PATH)),
                )
                {
                    let compare = match package {
                        Some(ref pkg) => pkg.ident.clone(),
                        None => self.current.clone(),
                    };

                    if cached.ident > compare {
                        package = Some(cached);
                    }
                }
            }

            if let Some(pkg) = package {
                self.current = pkg.ident.clone();
                sender.send(pkg).expect("Main thread has gone away!");
                break;
            }
            let time_to_wait = (next_check - SteadyTime::now()).num_milliseconds();
            if time_to_wait > 0 {
                thread::sleep(Duration::from_millis(time_to_wait as u64));
            }
        }
    }

    fn install(&mut self, package: &PackageIdent, recurse: bool) -> Result<PackageInstall> {
        let package = match PackageInstall::load(package, Some(&*FS_ROOT_PATH)) {
            Ok(pkg) => pkg,
            Err(_) => self.download(package)?,
        };
        if recurse {
            for ident in package.tdeps()?.iter() {
                self.install(&ident, false)?;
            }
        }
        Ok(package)
    }

    fn download(&mut self, package: &PackageIdent) -> Result<PackageInstall> {
        outputln!("Downloading {}", package);
        let mut archive = self.depot.fetch_package(
            package,
            &Path::new(&*FS_ROOT_PATH).join(
                CACHE_ARTIFACT_PATH,
            ),
            self.ui.progress(),
        )?;
        archive.verify(&default_cache_key_path(None))?;
        outputln!("Installing {}", package);
        archive.unpack(None)?;
        let pkg = PackageInstall::load(archive.ident().as_ref().unwrap(), Some(&*FS_ROOT_PATH))?;
        Ok(pkg)
    }

    fn update_frequency(&self) -> i64 {
        match env::var(FREQUENCY_ENVVAR) {
            Ok(val) => {
                match val.parse::<i64>() {
                    Ok(num) => num,
                    Err(_) => {
                        outputln!(
                            "Unable to parse '{}' from {} as a valid integer. Falling back \
                                  to default {} MS frequency.",
                            val,
                            FREQUENCY_ENVVAR,
                            DEFAULT_FREQUENCY
                        );
                        DEFAULT_FREQUENCY
                    }
                }
            }
            Err(_) => DEFAULT_FREQUENCY,
        }
    }
}
<|endoftext|>


<commit_before>use std::ffi::OsStr;
use walkdir::WalkDir;

use std::fs::File;
use std::io::prelude::*;

// The maximum length allowed for stderr files.
//
// We limit this because small files are easier to deal with than bigger files.
const LIMIT: usize = 245;

pub fn check() {
    let stderr_files = stderr_files();
    let exceeding_files = exceeding_stderr_files(stderr_files).collect::<Vec<String>>();

    if !exceeding_files.is_empty() {
        eprintln!("Error: stderr files exceeding limit of {} lines:", LIMIT);
        for path in exceeding_files {
            println!("{}", path);
        }
        std::process::exit(1);
    }
}

fn exceeding_stderr_files(files: impl Iterator<Item = walkdir::DirEntry>) -> impl Iterator<Item = String> {
    files.filter_map(|file| {
        let path = file.path().to_str().expect("Could not convert path to str").to_string();
        let linecount = count_linenumbers(&path);
        if linecount > LIMIT {
            Some(path)
        } else {
            None
        }
    })
}

fn stderr_files() -> impl Iterator<Item = walkdir::DirEntry> {
    // We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories.
    WalkDir::new("../tests/ui")
        .into_iter()
        .filter_map(std::result::Result::ok)
        .filter(|f| f.path().extension() == Some(OsStr::new("stderr")))
}

#[must_use]
fn count_linenumbers(filepath: &str) -> usize {
    if let Ok(mut file) = File::open(filepath) {
        let mut content = String::new();
        file.read_to_string(&mut content).expect("Failed to read file?");
        content.lines().count()
    } else {
        0
    }
}
<commit_msg>Decrease line length limit for stderr files<commit_after>use std::ffi::OsStr;
use walkdir::WalkDir;

use std::fs::File;
use std::io::prelude::*;

// The maximum length allowed for stderr files.
//
// We limit this because small files are easier to deal with than bigger files.
const LIMIT: usize = 220;

pub fn check() {
    let stderr_files = stderr_files();
    let exceeding_files = exceeding_stderr_files(stderr_files).collect::<Vec<String>>();

    if !exceeding_files.is_empty() {
        eprintln!("Error: stderr files exceeding limit of {} lines:", LIMIT);
        for path in exceeding_files {
            println!("{}", path);
        }
        std::process::exit(1);
    }
}

fn exceeding_stderr_files(files: impl Iterator<Item = walkdir::DirEntry>) -> impl Iterator<Item = String> {
    files.filter_map(|file| {
        let path = file.path().to_str().expect("Could not convert path to str").to_string();
        let linecount = count_linenumbers(&path);
        if linecount > LIMIT {
            Some(path)
        } else {
            None
        }
    })
}

fn stderr_files() -> impl Iterator<Item = walkdir::DirEntry> {
    // We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories.
    WalkDir::new("../tests/ui")
        .into_iter()
        .filter_map(std::result::Result::ok)
        .filter(|f| f.path().extension() == Some(OsStr::new("stderr")))
}

#[must_use]
fn count_linenumbers(filepath: &str) -> usize {
    if let Ok(mut file) = File::open(filepath) {
        let mut content = String::new();
        file.read_to_string(&mut content).expect("Failed to read file?");
        content.lines().count()
    } else {
        0
    }
}
<|endoftext|>


<commit_before>use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::TyS;
use rustc_session::{declare_lint_pass, declare_tool_lint};

use crate::utils::{is_type_lang_item, snippet_with_applicability, span_lint_and_sugg};

declare_clippy_lint! {
    /// **What it does:** Checks for redundant slicing expressions which use the full range, and
    /// do not change the type.
    ///
    /// **Why is this bad?** It unnecessarily adds complexity to the expression.
    ///
    /// **Known problems:** If the type being sliced has an implementation of `Index<RangeFull>`
    /// that actually changes anything then it can't be removed. However, this would be surprising
    /// to people reading the code and should have a note with it.
    ///
    /// **Example:**
    ///
    /// ```ignore
    /// fn get_slice(x: &[u32]) -> &[u32] {
    ///     &x[..]
    /// }
    /// ```
    /// Use instead:
    /// ```ignore
    /// fn get_slice(x: &[u32]) -> &[u32] {
    ///     x
    /// }
    /// ```
    pub REDUNDANT_SLICING,
    complexity,
    "redundant slicing of the whole range of a type"
}

declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING]);

impl LateLintPass<'_> for RedundantSlicing {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if_chain! {
            if let ExprKind::AddrOf(_, _, addressee) = expr.kind;
            if let ExprKind::Index(indexed, range) = addressee.kind;
            if is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull);
            if TyS::same_type(cx.typeck_results().expr_ty(expr), cx.typeck_results().expr_ty(indexed));
            then {
                let mut app = Applicability::MachineApplicable;
                let hint = snippet_with_applicability(cx, indexed.span, "..", &mut app).into_owned();

                span_lint_and_sugg(cx, REDUNDANT_SLICING, expr.span, "redundant slicing of the whole range",
                    "use the original slice instead", hint, app);
            }
        }
    }
}
<commit_msg>don't lint external macro expansions<commit_after>use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::{lint::in_external_macro, ty::TyS};
use rustc_session::{declare_lint_pass, declare_tool_lint};

use crate::utils::{is_type_lang_item, snippet_with_applicability, span_lint_and_sugg};

declare_clippy_lint! {
    /// **What it does:** Checks for redundant slicing expressions which use the full range, and
    /// do not change the type.
    ///
    /// **Why is this bad?** It unnecessarily adds complexity to the expression.
    ///
    /// **Known problems:** If the type being sliced has an implementation of `Index<RangeFull>`
    /// that actually changes anything then it can't be removed. However, this would be surprising
    /// to people reading the code and should have a note with it.
    ///
    /// **Example:**
    ///
    /// ```ignore
    /// fn get_slice(x: &[u32]) -> &[u32] {
    ///     &x[..]
    /// }
    /// ```
    /// Use instead:
    /// ```ignore
    /// fn get_slice(x: &[u32]) -> &[u32] {
    ///     x
    /// }
    /// ```
    pub REDUNDANT_SLICING,
    complexity,
    "redundant slicing of the whole range of a type"
}

declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING]);

impl LateLintPass<'_> for RedundantSlicing {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if in_external_macro(cx.sess, expr.span) {
            return;
        }

        if_chain! {
            if let ExprKind::AddrOf(_, _, addressee) = expr.kind;
            if let ExprKind::Index(indexed, range) = addressee.kind;
            if is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull);
            if TyS::same_type(cx.typeck_results().expr_ty(expr), cx.typeck_results().expr_ty(indexed));
            then {
                let mut app = Applicability::MachineApplicable;
                let hint = snippet_with_applicability(cx, indexed.span, "..", &mut app).into_owned();

                span_lint_and_sugg(cx, REDUNDANT_SLICING, expr.span, "redundant slicing of the whole range",
                    "use the original slice instead", hint, app);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! A rustification of the `AudioStreamBasicDescription` type.
//!
//! Find the original `AudioStreamBasicDescription` reference [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/c/tdef/AudioStreamBasicDescription).

use error::{self, Error};
use super::audio_format::AudioFormat;
use super::SampleFormat;
use sys;

/// A representation of the AudioStreamBasicDescription specifically for use with the AudioUnit API.
///
/// By using a type specific to the audio unit API, we can remove a lot of unnecessary boilerplate
/// that is normally associated with the AudioStreamBasicDescription.
///
/// Seeing as `LinearPCM` data (the `AudioFormat` used by the `AudioUnit` API) implies a single
/// frame per packet, we can infer many of the fields in an ASBD from the sample type.
///
/// `bytes_per_packet` = size_of::<S>()
/// `bytes_per_frame` = size_of::<S>()
/// `frames_per_packet` = 1
/// `bits_per_channel` = size_of::<S>() * 8
///
/// > A *packet* is a collection of one or more contiguous frames. In linear PCM audio, a packet is
/// always a single frame.
///
/// [from *Core Audio Overview*](https://developer.apple.com/library/ios/documentation/MusicAudio/Conceptual/CoreAudioOverview/WhatisCoreAudio/WhatisCoreAudio.html)
///
/// > The canonical formats in Core Audio are as follows:
/// >
/// > - iOS input and output: Linear PCM with 16-bit integer samples.
/// > - iOS audio units and other audio processing: Noninterleaved linear PCM with 8.24-bit
/// fixed-point samples
/// > - Mac input and output: Linear PCM with 32-bit floating point samples.
/// > - Mac audio units and other audio processing: Noninterleaved linear PCM with 32-bit floating
/// point samples.
#[derive(Copy, Clone, Debug)]
pub struct StreamFormat {
    /// The number of frames of audio data per second used to represent a signal.
    pub sample_rate: f64,
    /// The sample format used to represent the audio data.
    ///
    /// In OS X, Core Audio xpects audio data to be in native-endian, 32-bit floating-point,
    /// linear PCM format.
    ///
    /// iOS uses integer and fixed-point audio data. The result is faster calculations and less
    /// battery drain when processing audio. iOS provides a Converter audio unit and inclues the
    /// interfaces from Audio Converter Services (TODO: look into exposing this).
    pub sample_format: SampleFormat,
    pub flags: super::audio_format::LinearPcmFlags,
    pub channels_per_frame: u32,
}

impl StreamFormat {

    /// Convert an AudioStreamBasicDescription into a StreamFormat.
    ///
    /// Note: `audio_unit::StreamFormat` exclusively uses the `LinearPCM` `AudioFormat`. This is as
    /// specified in the documentation:
    ///
    /// > Specify kAudioFormatLinearPCM for the mFormatID field. Audio units use uncompressed audio
    /// data, so this is the correct format identifier to use whenever you work with audio units.
    ///
    /// [*Audio Unit Hosting Guide for iOS*](https://developer.apple.com/library/ios/documentation/MusicAudio/Conceptual/AudioUnitHostingGuide_iOS/AudioUnitHostingFundamentals/AudioUnitHostingFundamentals.html)
    ///
    /// Returns an `Error` if the `AudioFormat` inferred by the ASBD is not `LinearPCM`.
    ///
    /// Returns an `Error` if the sample format type kkkkkkkkkkkkkkkkkkkkkk
    #[allow(non_snake_case)]
    pub fn from_asbd(asbd: sys::AudioStreamBasicDescription) -> Result<StreamFormat, Error> {
        const NOT_SUPPORTED: Error = Error::AudioUnit(error::audio_unit::Error::FormatNotSupported);

        let sys::AudioStreamBasicDescription {
            mSampleRate,
            mFormatID,
            mFormatFlags,
            mBytesPerFrame,
            mChannelsPerFrame,
            ..
        } = asbd;

        // Retrieve the LinearPCM flags.
        let flags = match AudioFormat::from_format_and_flag(mFormatID, Some(mFormatFlags)) {
            Some(AudioFormat::LinearPCM(flags)) => flags,
            _ => return Err(NOT_SUPPORTED),
        };

        // Determine the `SampleFormat` to use.
        let sample_format = match SampleFormat::from_flags_and_bytes_per_frame(flags, mBytesPerFrame) {
            Some(sample_format) => sample_format,
            None => return Err(NOT_SUPPORTED),
        };

        Ok(StreamFormat {
            sample_rate: mSampleRate,
            flags: flags,
            sample_format: sample_format,
            channels_per_frame: mChannelsPerFrame,
        })
    }

    /// Convert a StreamFormat into an AudioStreamBasicDescription.
    pub fn to_asbd(self) -> sys::AudioStreamBasicDescription {
        let StreamFormat {
            sample_rate,
            flags,
            sample_format,
            channels_per_frame,
        } = self;

        let (format, maybe_flag) = AudioFormat::LinearPCM(flags).to_format_and_flag();

        let flag = maybe_flag.unwrap_or(::std::u32::MAX -2147483647);

        let bytes_per_frame = sample_format.size_in_bytes() as u32;
        const FRAMES_PER_PACKET: u32 = 1;
        let bytes_per_packet = bytes_per_frame * FRAMES_PER_PACKET;
        let bits_per_channel = bytes_per_frame * 8;

        sys::AudioStreamBasicDescription {
            mSampleRate: sample_rate,
            mFormatID: format,
            mFormatFlags: flag,
            mBytesPerPacket: bytes_per_packet,
            mFramesPerPacket: FRAMES_PER_PACKET,
            mBytesPerFrame: bytes_per_frame,
            mChannelsPerFrame: channels_per_frame,
            mBitsPerChannel: bits_per_channel,
            mReserved: 0,
        }
    }

}
<commit_msg>Fix math for computing bits_per_channel<commit_after>//! A rustification of the `AudioStreamBasicDescription` type.
//!
//! Find the original `AudioStreamBasicDescription` reference [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/c/tdef/AudioStreamBasicDescription).

use error::{self, Error};
use super::audio_format::AudioFormat;
use super::SampleFormat;
use sys;

/// A representation of the AudioStreamBasicDescription specifically for use with the AudioUnit API.
///
/// By using a type specific to the audio unit API, we can remove a lot of unnecessary boilerplate
/// that is normally associated with the AudioStreamBasicDescription.
///
/// Seeing as `LinearPCM` data (the `AudioFormat` used by the `AudioUnit` API) implies a single
/// frame per packet, we can infer many of the fields in an ASBD from the sample type.
///
/// `bytes_per_packet` = size_of::<S>()
/// `bytes_per_frame` = size_of::<S>()
/// `frames_per_packet` = 1
/// `bits_per_channel` = size_of::<S>() / channels_per_frame * 8
///
/// > A *packet* is a collection of one or more contiguous frames. In linear PCM audio, a packet is
/// always a single frame.
///
/// [from *Core Audio Overview*](https://developer.apple.com/library/ios/documentation/MusicAudio/Conceptual/CoreAudioOverview/WhatisCoreAudio/WhatisCoreAudio.html)
///
/// > The canonical formats in Core Audio are as follows:
/// >
/// > - iOS input and output: Linear PCM with 16-bit integer samples.
/// > - iOS audio units and other audio processing: Noninterleaved linear PCM with 8.24-bit
/// fixed-point samples
/// > - Mac input and output: Linear PCM with 32-bit floating point samples.
/// > - Mac audio units and other audio processing: Noninterleaved linear PCM with 32-bit floating
/// point samples.
#[derive(Copy, Clone, Debug)]
pub struct StreamFormat {
    /// The number of frames of audio data per second used to represent a signal.
    pub sample_rate: f64,
    /// The sample format used to represent the audio data.
    ///
    /// In OS X, Core Audio xpects audio data to be in native-endian, 32-bit floating-point,
    /// linear PCM format.
    ///
    /// iOS uses integer and fixed-point audio data. The result is faster calculations and less
    /// battery drain when processing audio. iOS provides a Converter audio unit and inclues the
    /// interfaces from Audio Converter Services (TODO: look into exposing this).
    pub sample_format: SampleFormat,
    pub flags: super::audio_format::LinearPcmFlags,
    pub channels_per_frame: u32,
}

impl StreamFormat {

    /// Convert an AudioStreamBasicDescription into a StreamFormat.
    ///
    /// Note: `audio_unit::StreamFormat` exclusively uses the `LinearPCM` `AudioFormat`. This is as
    /// specified in the documentation:
    ///
    /// > Specify kAudioFormatLinearPCM for the mFormatID field. Audio units use uncompressed audio
    /// data, so this is the correct format identifier to use whenever you work with audio units.
    ///
    /// [*Audio Unit Hosting Guide for iOS*](https://developer.apple.com/library/ios/documentation/MusicAudio/Conceptual/AudioUnitHostingGuide_iOS/AudioUnitHostingFundamentals/AudioUnitHostingFundamentals.html)
    ///
    /// Returns an `Error` if the `AudioFormat` inferred by the ASBD is not `LinearPCM`.
    ///
    /// Returns an `Error` if the sample format type kkkkkkkkkkkkkkkkkkkkkk
    #[allow(non_snake_case)]
    pub fn from_asbd(asbd: sys::AudioStreamBasicDescription) -> Result<StreamFormat, Error> {
        const NOT_SUPPORTED: Error = Error::AudioUnit(error::audio_unit::Error::FormatNotSupported);

        let sys::AudioStreamBasicDescription {
            mSampleRate,
            mFormatID,
            mFormatFlags,
            mBytesPerFrame,
            mChannelsPerFrame,
            ..
        } = asbd;

        // Retrieve the LinearPCM flags.
        let flags = match AudioFormat::from_format_and_flag(mFormatID, Some(mFormatFlags)) {
            Some(AudioFormat::LinearPCM(flags)) => flags,
            _ => return Err(NOT_SUPPORTED),
        };

        // Determine the `SampleFormat` to use.
        let sample_format = match SampleFormat::from_flags_and_bytes_per_frame(flags, mBytesPerFrame) {
            Some(sample_format) => sample_format,
            None => return Err(NOT_SUPPORTED),
        };

        Ok(StreamFormat {
            sample_rate: mSampleRate,
            flags: flags,
            sample_format: sample_format,
            channels_per_frame: mChannelsPerFrame,
        })
    }

    /// Convert a StreamFormat into an AudioStreamBasicDescription.
    pub fn to_asbd(self) -> sys::AudioStreamBasicDescription {
        let StreamFormat {
            sample_rate,
            flags,
            sample_format,
            channels_per_frame,
        } = self;

        let (format, maybe_flag) = AudioFormat::LinearPCM(flags).to_format_and_flag();

        let flag = maybe_flag.unwrap_or(::std::u32::MAX -2147483647);

        let bytes_per_frame = sample_format.size_in_bytes() as u32;
        const FRAMES_PER_PACKET: u32 = 1;
        let bytes_per_packet = bytes_per_frame * FRAMES_PER_PACKET;
        let bits_per_channel = bytes_per_frame / channels_per_frame * 8;

        sys::AudioStreamBasicDescription {
            mSampleRate: sample_rate,
            mFormatID: format,
            mFormatFlags: flag,
            mBytesPerPacket: bytes_per_packet,
            mFramesPerPacket: FRAMES_PER_PACKET,
            mBytesPerFrame: bytes_per_frame,
            mChannelsPerFrame: channels_per_frame,
            mBitsPerChannel: bits_per_channel,
            mReserved: 0,
        }
    }

}
<|endoftext|>


<commit_before>//mod signal_wrappers;

use std::io;
use std::fs::File;
use std::io::Write;
use std::collections::HashMap;
use api_parser::*;
use c_api_gen::get_type_name;
use c_api_gen::generate_c_function_args;
use c_api_gen::is_struct_pod;
use c_api_gen::callback_fun_def_name;

use heck::SnakeCase;
use heck::MixedCase;

fn generate_bind_info(info: &mut HashMap<String, Function>, func: &Function) {
    if !func.callback {
        return;
    }

    let mut input_args = String::new();

    for arg in &func.function_args {
        let tname = get_type_name(&arg);

        input_args.push_str(&tname);
        input_args.push_str(", ");
    }

    input_args.push_str("void*"); // user_data

    if info.contains_key(&input_args) {
        return;
    }

    info.insert(input_args.clone(), func.clone());
}

// generates signal wrappers for the variatos depending on input parameters
pub fn build_signal_wrappers_info(info: &mut HashMap<String, Function>, api_def: &ApiDef) {
    for sdef in &api_def.entries {
        for entry in &sdef.entries {
            match *entry {
                StructEntry::Function(ref func) => generate_bind_info(info, func),
                _ => (),
            }
        }
    }
}

fn signal_type_callback(func: &Function) -> String {
    let mut name_def = "Signal_".to_owned();

    for arg in &func.function_args {
        name_def.push_str(&arg.vtype);
        name_def.push_str("_")
    }

    name_def.push_str("void");
    name_def
}

// Generate a signal wrapper that is in the style of this:
//
//    class QSlotWrapperNoArgs : public QObject {
//        Q_OBJECT
//    public:
//        QSlotWrapperNoArgs(void* data, SignalNoArgs func) {
//            m_func = func;
//            m_data = data;
//        }
//
//        Q_SLOT void method() {
//            m_func(m_data);
//        }
//
//    private:
//        SignalNoArgs m_func;
//        void* m_data;
//    };
//
pub fn generate_signal_wrappers(f: &mut File, info: &HashMap<String, Function>) -> io::Result<()> {
    for (_, func) in info {
        let signal_type_name = signal_type_callback(func);

        f.write_all(b"///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n")?;

        f.write_fmt(format_args!("typedef void (*{})({});\n\n",
                                    signal_type_name,
                                    generate_c_function_args(func)))?;

        f.write_fmt(format_args!("class QSlotWrapper{} : public QObject {{\n    Q_OBJECT\npublic:\n", signal_type_name))?;
        f.write_fmt(format_args!("    QSlotWrapper{}(void* data, {} func) {{\n",
                                    signal_type_name,
                                    signal_type_name))?;
        f.write_all(b"        m_func = func;\n")?;
        f.write_all(b"        m_data = data;\n")?;
        f.write_all(b"    }\n\n")?;

        f.write_all(b"    Q_SLOT void method(")?;

        let args_count = func.function_args.len();

        if args_count > 0 {
            let mut input_args = String::new();

            for i in 0..args_count - 1 {
                let arg = &func.function_args[i];
                f.write_fmt(format_args!("{} {},", arg.vtype, arg.name))?;
                input_args.push_str(&arg.name);
                input_args.push_str(", ");
            }

            f.write_fmt(format_args!("{} {}) {{\n",
                                        get_type_name(&func.function_args[args_count - 1]),
                                        func.function_args[args_count - 1].name))?;
            input_args.push_str(&func.function_args[args_count - 1].name);

            f.write_fmt(format_args!("        m_func({}, m_data);\n", input_args))?;
        } else {
            f.write_all(b") {\n")?;
            f.write_all(b"        m_func(m_data);\n")?;
        }

        f.write_all(b"    }\n")?;

        f.write_all(b"private:\n")?;
        f.write_fmt(format_args!("    {} m_func;\n", signal_type_name))?;
        f.write_all(b"    void* m_data;\n")?;
        f.write_all(b"};\n\n")?;

    }

    Ok(())

}

fn function_name(struct_name: &str, func: &Function) -> String {
    format!("{}_{}", struct_name.to_snake_case(), func.name)
}

fn generate_func_def(f: &mut File,
                     struct_name: &str,
                     func: &Function,
                     struct_name_map: &HashMap<&str, &str>)
                     -> io::Result<()> {
    let ret_value;

    if let Some(ref ret_val) = func.return_val {
        ret_value = get_type_name(&ret_val);
    } else {
        ret_value = "void".to_owned();
    }

    // write return value and function name
    f.write_fmt(format_args!("static {} {}({}) {{ \n",
                                ret_value,
                                function_name(struct_name, func),
                                generate_c_function_args(func)))?;

    let struct_qt_name = struct_name_map
        .get(struct_name)
        .unwrap_or_else(|| &struct_name);

    // (changed from snake_case to camelCase matches the Qt function)

    // QWidget* qt_data = (QWidget*)priv_data;
    f.write_fmt(format_args!("    Q{}* qt_data = (Q{}*)priv_data;\n",
                                struct_qt_name,
                                struct_qt_name))?;

    // TODO: Handle return functions

    // qt_data->func(params);
    f.write_fmt(format_args!("    qt_data->{}(", func.name.to_mixed_case()))?;

    let args_count = func.function_args.len();

    if args_count > 0 {
        for i in 0..args_count - 1 {
            let arg = &func.function_args[i];
            // TODO: This is a hack for strings for now
            if arg.vtype == "String" {
                f.write_fmt(format_args!("QString::fromLatin1({}), ", &arg.name))?;
            } else {
                f.write_fmt(format_args!("{}, ", &arg.name))?;
            }
        }

        let arg = &func.function_args[args_count - 1];
        if arg.vtype == "String" {
            f.write_fmt(format_args!("QString::fromLatin1({})", &arg.name))?;
        } else {
            f.write_fmt(format_args!("{}", &arg.name))?;
        }
    }

    f.write_all(b");\n")?;
    f.write_all(b"}\n\n")?;

    Ok(())
}

///
///
///
///

fn func_def_callback(f: &mut File, struct_name: &str, func: &Function) -> io::Result<()> {
    let signal_type_name = signal_type_callback(func);
    let func_name = function_name(struct_name, func);

    println!("struct_name {}", struct_name);

    f.write_fmt(format_args!("static {} {{\n", callback_fun_def_name(false, &func_name, func)))?;

    //QSlotWrapperNoArgs* wrap = new QSlotWrapperNoArgs(reciver, (SignalNoArgs)callback);
    f.write_fmt(format_args!("    QSlotWrapper{}* wrap = new QSlotWrapper{}(user_data, ({})callback);\n", signal_type_name, signal_type_name, signal_type_name))?;
    f.write_all(b"    QObject* q_obj = (QObject*)object;\n")?;

    f.write_fmt(format_args!("    QObject::connect(q_obj, SIGNAL({}(",
                                func.name.to_mixed_case()))?;

    func.write_c_func_def(f, |_, arg| (get_type_name(arg), "".to_owned()))?;

    f.write_all(b"), wrap, SLOT(method(")?;

    func.write_c_func_def(f, |_, arg| (get_type_name(arg), "".to_owned()))?;

    f.write_all(b"));\n")?;
    f.write_all(b"}\n\n")?;

    Ok(())
}

///
///
///
///
fn generate_struct_body_recursive(f: &mut File,
                                  name: &str,
                                  sdef: &Struct,
                                  struct_name_map: &HashMap<&str, &str>,
                                  api_def: &ApiDef)
                                  -> io::Result<()> {
    if let Some(ref inherit_name) = sdef.inherit {
        for sdef in &api_def.entries {
            if &sdef.name == inherit_name {
                generate_struct_body_recursive(f, name, &sdef, struct_name_map, api_def)?;
            }
        }
    }

    for entry in &sdef.entries {
        match *entry {
            StructEntry::Function(ref func) => {
                f.write_all(b"///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n")?;

                if func.callback == false {
                    generate_func_def(f, name, func, struct_name_map)?;
                } else {
                    func_def_callback(f, name, func)?;
                }
            }

            _ => (),
        }
    }

    Ok(())
}

///
/// Generate includes from all the structs which are non-pod
///
fn generate_includes(f: &mut File,
                     struct_name_map: &HashMap<&str, &str>,
                     api_def: &ApiDef)
                     -> io::Result<()> {
    for sdef in &api_def.entries {
        let struct_name = sdef.name.as_str();

        if is_struct_pod(sdef) {
            continue;
        }

        let struct_qt_name = struct_name_map
            .get(struct_name)
            .unwrap_or_else(|| &struct_name);
        f.write_fmt(format_args!("#include <Q{}>\n", struct_qt_name))?;
    }

    Ok(())
}

///
/// Generate the struct defs
///
fn generate_struct_def(f: &mut File, struct_name: &str, api_def: &ApiDef, sdef: &Struct) -> io::Result<()> {
    if let Some(ref inherit_name) = sdef.inherit {
        for sdef in &api_def.entries {
            if &sdef.name == inherit_name {
                generate_struct_def(f, struct_name, api_def, &sdef)?;
            }
        }
    }

    for entry in &sdef.entries {
        match *entry {
            StructEntry::Function(ref func) => {
                if func.callback {
                    f.write_fmt(format_args!("    connect_{},\n", function_name(struct_name, func)))?;
                } else {
                    f.write_fmt(format_args!("    {},\n", function_name(struct_name, func)))?;
                }
            }

            _ => (),
        }
    }

    Ok(())
}

///
///
///
///
///
fn generate_struct_defs(f: &mut File, api_def: &ApiDef) -> io::Result<()> {
    for sdef in &api_def.entries {
        if is_struct_pod(sdef) {
            continue;
        }

        f.write_all(b"///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n")?;
        f.write_fmt(format_args!("static struct PU{} s_{} = {{\n", sdef.name, sdef.name.to_snake_case()))?;

        generate_struct_def(f, &sdef.name, api_def, sdef)?;

        f.write_all(b"    0,\n")?;
        f.write_all(b"};\n\n")?;
    }

    Ok(())
}

///
/// This is the main entry for generating the C/C++ buindings for Qt. The current API mimics Qt
/// fairly closely when it comes to names but at the start there is a map setup that used used
/// to translate between some struct names to fit the Qt version. If more structs gets added that
/// needs to be translated into another Qt name they needs to be added here as well
///

pub fn generate_qt_bindings(filename: &str, api_def: &ApiDef) -> io::Result<()> {
    let mut f = File::create(filename)?;
    let mut signals_info = HashMap::new();

    let mut struct_name_map = HashMap::new();

    struct_name_map.insert("Button", "AbstractButton");

    f.write_all(b"#include \"c_api.h\"\n")?;

    generate_includes(&mut f, &struct_name_map, api_def)?;
    build_signal_wrappers_info(&mut signals_info, api_def);
    generate_signal_wrappers(&mut f, &signals_info)?;

    // generate wrapper functions

    for sdef in &api_def.entries {
        generate_struct_body_recursive(&mut f, &sdef.name, &sdef, &struct_name_map, api_def)?;
    }

    generate_struct_defs(&mut f, api_def)?;

    Ok(())
}
<commit_msg>RustFmt<commit_after>//mod signal_wrappers;

use std::io;
use std::fs::File;
use std::io::Write;
use std::collections::HashMap;
use api_parser::*;
use c_api_gen::get_type_name;
use c_api_gen::generate_c_function_args;
use c_api_gen::is_struct_pod;
use c_api_gen::callback_fun_def_name;

use heck::SnakeCase;
use heck::MixedCase;

fn generate_bind_info(info: &mut HashMap<String, Function>, func: &Function) {
    if !func.callback {
        return;
    }

    let mut input_args = String::new();

    for arg in &func.function_args {
        let tname = get_type_name(&arg);

        input_args.push_str(&tname);
        input_args.push_str(", ");
    }

    input_args.push_str("void*"); // user_data

    if info.contains_key(&input_args) {
        return;
    }

    info.insert(input_args.clone(), func.clone());
}

// generates signal wrappers for the variatos depending on input parameters
pub fn build_signal_wrappers_info(info: &mut HashMap<String, Function>, api_def: &ApiDef) {
    for sdef in &api_def.entries {
        for entry in &sdef.entries {
            match *entry {
                StructEntry::Function(ref func) => generate_bind_info(info, func),
                _ => (),
            }
        }
    }
}

fn signal_type_callback(func: &Function) -> String {
    let mut name_def = "Signal_".to_owned();

    for arg in &func.function_args {
        name_def.push_str(&arg.vtype);
        name_def.push_str("_")
    }

    name_def.push_str("void");
    name_def
}

// Generate a signal wrapper that is in the style of this:
//
//    class QSlotWrapperNoArgs : public QObject {
//        Q_OBJECT
//    public:
//        QSlotWrapperNoArgs(void* data, SignalNoArgs func) {
//            m_func = func;
//            m_data = data;
//        }
//
//        Q_SLOT void method() {
//            m_func(m_data);
//        }
//
//    private:
//        SignalNoArgs m_func;
//        void* m_data;
//    };
//
pub fn generate_signal_wrappers(f: &mut File, info: &HashMap<String, Function>) -> io::Result<()> {
    for (_, func) in info {
        let signal_type_name = signal_type_callback(func);

        f.write_all(b"///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n")?;

        f.write_fmt(format_args!("typedef void (*{})({});\n\n",
                                    signal_type_name,
                                    generate_c_function_args(func)))?;

        f.write_fmt(format_args!("class QSlotWrapper{} : public QObject {{\n    Q_OBJECT\npublic:\n", signal_type_name))?;
        f.write_fmt(format_args!("    QSlotWrapper{}(void* data, {} func) {{\n",
                                    signal_type_name,
                                    signal_type_name))?;
        f.write_all(b"        m_func = func;\n")?;
        f.write_all(b"        m_data = data;\n")?;
        f.write_all(b"    }\n\n")?;

        f.write_all(b"    Q_SLOT void method(")?;

        let args_count = func.function_args.len();

        if args_count > 0 {
            let mut input_args = String::new();

            for i in 0..args_count - 1 {
                let arg = &func.function_args[i];
                f.write_fmt(format_args!("{} {},", arg.vtype, arg.name))?;
                input_args.push_str(&arg.name);
                input_args.push_str(", ");
            }

            f.write_fmt(format_args!("{} {}) {{\n",
                                        get_type_name(&func.function_args[args_count - 1]),
                                        func.function_args[args_count - 1].name))?;
            input_args.push_str(&func.function_args[args_count - 1].name);

            f.write_fmt(format_args!("        m_func({}, m_data);\n", input_args))?;
        } else {
            f.write_all(b") {\n")?;
            f.write_all(b"        m_func(m_data);\n")?;
        }

        f.write_all(b"    }\n")?;

        f.write_all(b"private:\n")?;
        f.write_fmt(format_args!("    {} m_func;\n", signal_type_name))?;
        f.write_all(b"    void* m_data;\n")?;
        f.write_all(b"};\n\n")?;

    }

    Ok(())

}

fn function_name(struct_name: &str, func: &Function) -> String {
    format!("{}_{}", struct_name.to_snake_case(), func.name)
}

fn generate_func_def(f: &mut File,
                     struct_name: &str,
                     func: &Function,
                     struct_name_map: &HashMap<&str, &str>)
                     -> io::Result<()> {
    let ret_value;

    if let Some(ref ret_val) = func.return_val {
        ret_value = get_type_name(&ret_val);
    } else {
        ret_value = "void".to_owned();
    }

    // write return value and function name
    f.write_fmt(format_args!("static {} {}({}) {{ \n",
                                ret_value,
                                function_name(struct_name, func),
                                generate_c_function_args(func)))?;

    let struct_qt_name = struct_name_map
        .get(struct_name)
        .unwrap_or_else(|| &struct_name);

    // (changed from snake_case to camelCase matches the Qt function)

    // QWidget* qt_data = (QWidget*)priv_data;
    f.write_fmt(format_args!("    Q{}* qt_data = (Q{}*)priv_data;\n",
                                struct_qt_name,
                                struct_qt_name))?;

    // TODO: Handle return functions

    // qt_data->func(params);
    f.write_fmt(format_args!("    qt_data->{}(", func.name.to_mixed_case()))?;

    let args_count = func.function_args.len();

    if args_count > 0 {
        for i in 0..args_count - 1 {
            let arg = &func.function_args[i];
            // TODO: This is a hack for strings for now
            if arg.vtype == "String" {
                f.write_fmt(format_args!("QString::fromLatin1({}), ", &arg.name))?;
            } else {
                f.write_fmt(format_args!("{}, ", &arg.name))?;
            }
        }

        let arg = &func.function_args[args_count - 1];
        if arg.vtype == "String" {
            f.write_fmt(format_args!("QString::fromLatin1({})", &arg.name))?;
        } else {
            f.write_fmt(format_args!("{}", &arg.name))?;
        }
    }

    f.write_all(b");\n")?;
    f.write_all(b"}\n\n")?;

    Ok(())
}

///
///
///
///

fn func_def_callback(f: &mut File, struct_name: &str, func: &Function) -> io::Result<()> {
    let signal_type_name = signal_type_callback(func);
    let func_name = function_name(struct_name, func);

    println!("struct_name {}", struct_name);

    f.write_fmt(format_args!("static {} {{\n",
                                callback_fun_def_name(false, &func_name, func)))?;

    //QSlotWrapperNoArgs* wrap = new QSlotWrapperNoArgs(reciver, (SignalNoArgs)callback);
    f.write_fmt(format_args!("    QSlotWrapper{}* wrap = new QSlotWrapper{}(user_data, ({})callback);\n", signal_type_name, signal_type_name, signal_type_name))?;
    f.write_all(b"    QObject* q_obj = (QObject*)object;\n")?;

    f.write_fmt(format_args!("    QObject::connect(q_obj, SIGNAL({}(",
                                func.name.to_mixed_case()))?;

    func.write_c_func_def(f, |_, arg| (get_type_name(arg), "".to_owned()))?;

    f.write_all(b"), wrap, SLOT(method(")?;

    func.write_c_func_def(f, |_, arg| (get_type_name(arg), "".to_owned()))?;

    f.write_all(b"));\n")?;
    f.write_all(b"}\n\n")?;

    Ok(())
}

///
///
///
///
fn generate_struct_body_recursive(f: &mut File,
                                  name: &str,
                                  sdef: &Struct,
                                  struct_name_map: &HashMap<&str, &str>,
                                  api_def: &ApiDef)
                                  -> io::Result<()> {
    if let Some(ref inherit_name) = sdef.inherit {
        for sdef in &api_def.entries {
            if &sdef.name == inherit_name {
                generate_struct_body_recursive(f, name, &sdef, struct_name_map, api_def)?;
            }
        }
    }

    for entry in &sdef.entries {
        match *entry {
            StructEntry::Function(ref func) => {
                f.write_all(b"///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n")?;

                if func.callback == false {
                    generate_func_def(f, name, func, struct_name_map)?;
                } else {
                    func_def_callback(f, name, func)?;
                }
            }

            _ => (),
        }
    }

    Ok(())
}

///
/// Generate includes from all the structs which are non-pod
///
fn generate_includes(f: &mut File,
                     struct_name_map: &HashMap<&str, &str>,
                     api_def: &ApiDef)
                     -> io::Result<()> {
    for sdef in &api_def.entries {
        let struct_name = sdef.name.as_str();

        if is_struct_pod(sdef) {
            continue;
        }

        let struct_qt_name = struct_name_map
            .get(struct_name)
            .unwrap_or_else(|| &struct_name);
        f.write_fmt(format_args!("#include <Q{}>\n", struct_qt_name))?;
    }

    Ok(())
}

///
/// Generate the struct defs
///
fn generate_struct_def(f: &mut File,
                       struct_name: &str,
                       api_def: &ApiDef,
                       sdef: &Struct)
                       -> io::Result<()> {
    if let Some(ref inherit_name) = sdef.inherit {
        for sdef in &api_def.entries {
            if &sdef.name == inherit_name {
                generate_struct_def(f, struct_name, api_def, &sdef)?;
            }
        }
    }

    for entry in &sdef.entries {
        match *entry {
            StructEntry::Function(ref func) => {
                if func.callback {
                    f.write_fmt(format_args!("    connect_{},\n",
                                                function_name(struct_name, func)))?;
                } else {
                    f.write_fmt(format_args!("    {},\n", function_name(struct_name, func)))?;
                }
            }

            _ => (),
        }
    }

    Ok(())
}

///
///
///
///
///
fn generate_struct_defs(f: &mut File, api_def: &ApiDef) -> io::Result<()> {
    for sdef in &api_def.entries {
        if is_struct_pod(sdef) {
            continue;
        }

        f.write_all(b"///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n")?;
        f.write_fmt(format_args!("static struct PU{} s_{} = {{\n",
                                    sdef.name,
                                    sdef.name.to_snake_case()))?;

        generate_struct_def(f, &sdef.name, api_def, sdef)?;

        f.write_all(b"    0,\n")?;
        f.write_all(b"};\n\n")?;
    }

    Ok(())
}

///
/// This is the main entry for generating the C/C++ buindings for Qt. The current API mimics Qt
/// fairly closely when it comes to names but at the start there is a map setup that used used
/// to translate between some struct names to fit the Qt version. If more structs gets added that
/// needs to be translated into another Qt name they needs to be added here as well
///

pub fn generate_qt_bindings(filename: &str, api_def: &ApiDef) -> io::Result<()> {
    let mut f = File::create(filename)?;
    let mut signals_info = HashMap::new();

    let mut struct_name_map = HashMap::new();

    struct_name_map.insert("Button", "AbstractButton");

    f.write_all(b"#include \"c_api.h\"\n")?;

    generate_includes(&mut f, &struct_name_map, api_def)?;
    build_signal_wrappers_info(&mut signals_info, api_def);
    generate_signal_wrappers(&mut f, &signals_info)?;

    // generate wrapper functions

    for sdef in &api_def.entries {
        generate_struct_body_recursive(&mut f, &sdef.name, &sdef, &struct_name_map, api_def)?;
    }

    generate_struct_defs(&mut f, api_def)?;

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2016 The Noise-rs Developers.
//
// 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 num_traits::Float;
use math::interp;
use NoiseModule;

/// Noise module that outputs the weighted blend of the output values from two
/// source modules given the output value supplied by a control module.
#[derive(Clone, Debug)]
pub struct Blend<Source1, Source2, Control> {
    /// Outputs one of the values to blend.
    pub source1: Source1,

    /// Outputs one of the values to blend.
    pub source2: Source2,

    /// Determines the weight of the blending operation. Negative values weight
    /// the blend towards the output value from the _Source1_ module. Positive
    /// values weight the blend towards the output value from the _Source2_
    /// module.
    pub control: Control,
}

impl<Source1, Source2, Control> Blend<Source1, Source2, Control> {
    pub fn new(source1: Source1,
               source2: Source2,
               control: Control)
               -> Blend<Source1, Source2, Control> {
        Blend {
            source1: source1,
            source2: source2,
            control: control,
        }
    }
}

impl<Source1, Source2, Control, T, U> NoiseModule<T> for Blend<Source1, Source2, Control>
    where Source1: NoiseModule<T, Output = U>,
          Source2: NoiseModule<T, Output = U>,
          Control: NoiseModule<T, Output = U>,
          T: Copy,
          U: Float,
{
    type Output = U;

    fn get(&self, point: T) -> Self::Output {
        let lower = self.source1.get(point);
        let upper = self.source2.get(point);
        let control = self.control.get(point);

        interp::linear(lower, upper, control)
    }
}
<commit_msg>Edit the documentation for Blend<commit_after>// Copyright 2016 The Noise-rs Developers.
//
// 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 num_traits::Float;
use math::interp;
use NoiseModule;

/// Noise module that outputs a weighted blend of the output values from two
/// source modules given the output value supplied by a control module.
///
/// This noise module uses linear interpolation to perform the blending
/// operation.
#[derive(Clone, Debug)]
pub struct Blend<Source1, Source2, Control> {
    /// Outputs one of the values to blend.
    pub source1: Source1,

    /// Outputs one of the values to blend.
    pub source2: Source2,

    /// Determines the weight of the blending operation. Negative values weight
    /// the blend towards the output value from the `source1` module. Positive
    /// values weight the blend towards the output value from the `source2`
    /// module.
    pub control: Control,
}

impl<Source1, Source2, Control> Blend<Source1, Source2, Control> {
    pub fn new(source1: Source1,
               source2: Source2,
               control: Control)
               -> Blend<Source1, Source2, Control> {
        Blend {
            source1: source1,
            source2: source2,
            control: control,
        }
    }
}

impl<Source1, Source2, Control, T, U> NoiseModule<T> for Blend<Source1, Source2, Control>
    where Source1: NoiseModule<T, Output = U>,
          Source2: NoiseModule<T, Output = U>,
          Control: NoiseModule<T, Output = U>,
          T: Copy,
          U: Float,
{
    type Output = U;

    fn get(&self, point: T) -> Self::Output {
        let lower = self.source1.get(point);
        let upper = self.source2.get(point);
        let control = self.control.get(point);

        interp::linear(lower, upper, control)
    }
}
<|endoftext|>