<commit_before>use super::{component::prompt::log::Log, selection::Selection};
use crate::user::Users;
use crate::{config::Config, util::ArcMutex};
use crate::{database::Database, series::LastWatched};
use crate::{file::SerializedFile, key::Key};
use crate::{remote::RemoteLogin, series::info::SeriesInfo};
use crate::{
    remote::RemoteStatus,
    series::{LoadedSeries, Series, SeriesData},
};
use crate::{series::config::SeriesConfig, Args};
use crate::{try_opt_ret, util::arc_mutex};
use anime::remote::{anilist::AniList, Remote};
use anime::{local::SortedEpisodes, remote::anilist::Auth};
use anyhow::{anyhow, Context, Result};
use chrono::{DateTime, Utc};
use crossterm::event::{Event, EventStream};
use futures::{select, FutureExt, StreamExt};
use parking_lot::MutexGuard;
use std::{borrow::Cow, mem, ops::Deref, sync::Arc};
use tokio::{
    process::Child,
    signal::unix::{signal, Signal, SignalKind},
    sync::{broadcast, Notify},
    task,
};

pub struct UIState {
    pub series: Selection<LoadedSeries>,
    pub last_watched: LastWatched,
    pub input_state: InputState,
    pub events: broadcast::Sender<StateEvent>,
    pub log: Log<'static>,
    pub config: Config,
    pub users: Users,
    pub remote: RemoteStatus,
    pub db: Database,
}

impl UIState {
    pub fn init() -> Result<Self> {
        let config = Config::load_or_create().context("failed to load / create config")?;
        let users = Users::load_or_create().context("failed to load / create users")?;
        let db = Database::open().context("failed to open database")?;
        let last_watched = LastWatched::load().context("last watched series")?;

        let mut series = SeriesConfig::load_all(&db)
            .context("failed to load series configs")?
            .into_iter()
            .map(|sconfig| Series::load_from_config(sconfig, &config, &db))
            .collect::<Vec<_>>();

        series.sort_unstable();

        let (events_tx, _) = broadcast::channel(8);

        Ok(Self {
            series: Selection::new(series),
            last_watched,
            input_state: InputState::default(),
            events: events_tx,
            log: Log::new(15),
            config,
            users,
            remote: RemoteStatus::LoggedIn(Remote::offline()),
            db,
        })
    }

    pub fn select_initial_series(&mut self, args: &Args) -> Result<()> {
        let mut desired_series = args.series.as_ref().map(Cow::Borrowed);

        if desired_series.is_none() {
            let last_watched = LastWatched::load().context("loading last watched series")?;
            desired_series = last_watched.take().map(Cow::Owned);
        }

        let selected = match desired_series {
            Some(desired) => self
                .series
                .iter()
                .position(|series| series.nickname() == desired.as_ref())
                .unwrap_or(0),
            None => 0,
        };

        self.series.set_selected(selected);
        self.init_selected_series();

        Ok(())
    }

    pub fn add_series<E>(
        &mut self,
        config: SeriesConfig,
        info: SeriesInfo,
        episodes: E,
    ) -> Result<()>
    where
        E: Into<Option<SortedEpisodes>>,
    {
        let remote = self.remote.get_logged_in()?;
        let data = SeriesData::from_remote(config, info, remote)?;

        let series = match episodes.into() {
            Some(episodes) => LoadedSeries::Complete(Series::with_episodes(data, episodes)),
            None => Series::init(data, &self.config),
        };

        series.save(&self.db)?;

        let nickname = series.nickname().to_string();

        self.series.push(series);
        self.series.items_mut().sort_unstable();

        let selected = self
            .series
            .iter()
            .position(|s| s.nickname() == nickname)
            .unwrap_or(0);

        self.series.set_selected(selected);
        Ok(())
    }

    pub fn init_selected_series(&mut self) {
        let selected = try_opt_ret!(self.series.selected_mut());
        selected.try_load(&self.config, &self.db)
    }

    pub fn delete_selected_series(&mut self) -> Result<LoadedSeries> {
        let series = match self.series.remove_selected() {
            Some(series) => series,
            None => return Err(anyhow!("must select series to delete")),
        };

        // Since we changed our selected series, we need to make sure the new one is initialized
        self.init_selected_series();

        series.config().delete(&self.db)?;
        Ok(series)
    }

    async fn start_next_series_episode(state: &mut UIState) -> Result<(Child, ProgressTime)> {
        let series = match state.series.valid_selection_mut() {
            Some(series) => series,
            None => return Err(anyhow!("no series selected")),
        };

        let is_diff_series = state.last_watched.set(&series.data.config.nickname);

        if is_diff_series {
            state
                .last_watched
                .save()
                .context("setting last watched series")?;
        }

        let remote = state.remote.get_logged_in()?;

        series
            .begin_watching(remote, &state.config, &state.db)
            .context("updating series status")?;

        let next_ep = series.data.entry.watched_episodes() + 1;

        let child = series
            .play_episode(next_ep as u32, &state.config)
            .context("playing episode")?;

        let progress_time = series.data.next_watch_progress_time(&state.config);

        Ok((child, progress_time))
    }

    async fn track_episode_finish(
        mut ep_process: Child,
        progress_time: ProgressTime,
        state: &SharedState,
    ) -> Result<()> {
        ep_process
            .wait()
            .await
            .context("waiting for episode to finish")?;

        let mut state = state.lock();
        let state = state.get_mut();

        state.input_state.reset();

        if Utc::now() < progress_time {
            return Ok(());
        }

        let series = if let Some(series) = state.series.valid_selection_mut() {
            series
        } else {
            return Ok(());
        };

        let remote = state.remote.get_logged_in()?;

        series
            .episode_completed(remote, &state.config, &state.db)
            .context("marking episode as completed")
    }

    pub async fn play_next_series_episode(&mut self, shared_state: &SharedState) -> Result<()> {
        let (ep_process, progress_time) = Self::start_next_series_episode(self).await?;

        self.events
            .send(StateEvent::StartedEpisode(progress_time))
            .ok();

        self.input_state = InputState::Locked;

        let shared_state = shared_state.clone();

        task::spawn(async move {
            let result = Self::track_episode_finish(ep_process, progress_time, &shared_state).await;

            let mut state = shared_state.lock();
            let state = state.get_mut();

            if let Err(err) = result {
                state.log.push_error(&err);
            }

            state.input_state.reset();
            state.events.send(StateEvent::FinishedEpisode).ok();
        });

        Ok(())
    }
}

pub type ReactiveState = Reactive<UIState>;

#[derive(Clone)]
pub struct SharedState(ArcMutex<ReactiveState>);

impl SharedState {
    pub fn new(state: ReactiveState) -> Self {
        Self(arc_mutex(state))
    }

    pub fn login_to_remote_async(&self, login: RemoteLogin) {
        let shared_state = self.clone();

        task::spawn_blocking(move || match login {
            RemoteLogin::AniList(username, token) => {
                {
                    let mut state = shared_state.lock();
                    state.get_mut().remote = RemoteStatus::LoggingIn(username);
                }

                let auth = Auth::retrieve(token);
                let mut state = shared_state.lock();
                let state = state.get_mut();

                let remote = match auth {
                    Ok(auth) => {
                        let anilist = AniList::Authenticated(auth);
                        RemoteStatus::LoggedIn(anilist.into())
                    }
                    Err(err) => {
                        state.log.push_error(&err.into());
                        RemoteStatus::LoggedIn(Remote::offline())
                    }
                };

                state.remote = remote;
            }
        });
    }

    #[inline(always)]
    pub fn lock(&self) -> MutexGuard<'_, ReactiveState> {
        self.0.lock()
    }
}

#[derive(Clone, Copy)]
pub enum InputState {
    Idle,
    Locked,
    FocusedOnMainPanel,
    EnteringCommand,
}

impl InputState {
    #[inline(always)]
    pub fn reset(&mut self) {
        *self = Self::default();
    }
}

impl Default for InputState {
    fn default() -> Self {
        Self::Idle
    }
}

impl PartialEq for InputState {
    fn eq(&self, other: &Self) -> bool {
        mem::discriminant(self) == mem::discriminant(other)
    }
}

pub type ProgressTime = DateTime<Utc>;

#[derive(Debug, Clone)]
pub enum StateEvent {
    StartedEpisode(ProgressTime),
    FinishedEpisode,
}

pub struct Reactive<T> {
    state: T,
    pub dirty: Arc<Notify>,
}

impl<T> Reactive<T> {
    pub const fn new(state: T, dirty: Arc<Notify>) -> Self {
        Self { state, dirty }
    }

    #[inline(always)]
    pub fn get(&self) -> &T {
        &self.state
    }

    pub fn get_mut(&mut self) -> &mut T {
        self.mark_dirty();
        &mut self.state
    }

    #[inline(always)]
    pub fn mark_dirty(&mut self) {
        self.dirty.notify_waiters()
    }
}

impl<T> Deref for Reactive<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        self.get()
    }
}

#[derive(Debug)]
pub enum UIEvent {
    Key(Key),
    StateChange,
    Resize,
}

pub enum UIErrorKind {
    ExitRequest,
    Other(anyhow::Error),
}

pub type UIEventError<T> = std::result::Result<T, UIErrorKind>;

pub struct UIEvents {
    reader: EventStream,
    resize_event_stream: Signal,
}

impl UIEvents {
    pub fn new() -> Result<Self> {
        let resize_event_stream =
            signal(SignalKind::window_change()).context("SIGWINCH signal capture failed")?;

        Ok(Self {
            reader: EventStream::new(),
            resize_event_stream,
        })
    }

    #[allow(clippy::mut_mut)]
    pub async fn next(&mut self, state_change: &Notify) -> UIEventError<Option<UIEvent>> {
        let state_change = state_change.notified().fuse();
        tokio::pin!(state_change);

        let window_resize = self.resize_event_stream.recv().fuse();
        tokio::pin!(window_resize);

        let mut next_event = self.reader.next().fuse();

        select! {
            _ = state_change => Ok(Some(UIEvent::StateChange)),
            _ = window_resize => Ok(Some(UIEvent::Resize)),
            event = next_event => match event {
                Some(Ok(Event::Key(key))) => Ok(Some(UIEvent::Key(Key::new(key)))),
                Some(Ok(_)) => Ok(None),
                Some(Err(err)) => Err(UIErrorKind::Other(err.into())),
                None => Err(UIErrorKind::ExitRequest),
            }
        }
    }
}
<commit_msg>anup: Move UIState::track_episode_finish() function to SharedState struct<commit_after>use super::{component::prompt::log::Log, selection::Selection};
use crate::user::Users;
use crate::{config::Config, util::ArcMutex};
use crate::{database::Database, series::LastWatched};
use crate::{file::SerializedFile, key::Key};
use crate::{remote::RemoteLogin, series::info::SeriesInfo};
use crate::{
    remote::RemoteStatus,
    series::{LoadedSeries, Series, SeriesData},
};
use crate::{series::config::SeriesConfig, Args};
use crate::{try_opt_ret, util::arc_mutex};
use anime::remote::{anilist::AniList, Remote};
use anime::{local::SortedEpisodes, remote::anilist::Auth};
use anyhow::{anyhow, Context, Result};
use chrono::{DateTime, Utc};
use crossterm::event::{Event, EventStream};
use futures::{select, FutureExt, StreamExt};
use parking_lot::MutexGuard;
use std::{borrow::Cow, mem, ops::Deref, sync::Arc};
use tokio::{
    process::Child,
    signal::unix::{signal, Signal, SignalKind},
    sync::{broadcast, Notify},
    task,
};

pub struct UIState {
    pub series: Selection<LoadedSeries>,
    pub last_watched: LastWatched,
    pub input_state: InputState,
    pub events: broadcast::Sender<StateEvent>,
    pub log: Log<'static>,
    pub config: Config,
    pub users: Users,
    pub remote: RemoteStatus,
    pub db: Database,
}

impl UIState {
    pub fn init() -> Result<Self> {
        let config = Config::load_or_create().context("failed to load / create config")?;
        let users = Users::load_or_create().context("failed to load / create users")?;
        let db = Database::open().context("failed to open database")?;
        let last_watched = LastWatched::load().context("last watched series")?;

        let mut series = SeriesConfig::load_all(&db)
            .context("failed to load series configs")?
            .into_iter()
            .map(|sconfig| Series::load_from_config(sconfig, &config, &db))
            .collect::<Vec<_>>();

        series.sort_unstable();

        let (events_tx, _) = broadcast::channel(8);

        Ok(Self {
            series: Selection::new(series),
            last_watched,
            input_state: InputState::default(),
            events: events_tx,
            log: Log::new(15),
            config,
            users,
            remote: RemoteStatus::LoggedIn(Remote::offline()),
            db,
        })
    }

    pub fn select_initial_series(&mut self, args: &Args) -> Result<()> {
        let mut desired_series = args.series.as_ref().map(Cow::Borrowed);

        if desired_series.is_none() {
            let last_watched = LastWatched::load().context("loading last watched series")?;
            desired_series = last_watched.take().map(Cow::Owned);
        }

        let selected = match desired_series {
            Some(desired) => self
                .series
                .iter()
                .position(|series| series.nickname() == desired.as_ref())
                .unwrap_or(0),
            None => 0,
        };

        self.series.set_selected(selected);
        self.init_selected_series();

        Ok(())
    }

    pub fn add_series<E>(
        &mut self,
        config: SeriesConfig,
        info: SeriesInfo,
        episodes: E,
    ) -> Result<()>
    where
        E: Into<Option<SortedEpisodes>>,
    {
        let remote = self.remote.get_logged_in()?;
        let data = SeriesData::from_remote(config, info, remote)?;

        let series = match episodes.into() {
            Some(episodes) => LoadedSeries::Complete(Series::with_episodes(data, episodes)),
            None => Series::init(data, &self.config),
        };

        series.save(&self.db)?;

        let nickname = series.nickname().to_string();

        self.series.push(series);
        self.series.items_mut().sort_unstable();

        let selected = self
            .series
            .iter()
            .position(|s| s.nickname() == nickname)
            .unwrap_or(0);

        self.series.set_selected(selected);
        Ok(())
    }

    pub fn init_selected_series(&mut self) {
        let selected = try_opt_ret!(self.series.selected_mut());
        selected.try_load(&self.config, &self.db)
    }

    pub fn delete_selected_series(&mut self) -> Result<LoadedSeries> {
        let series = match self.series.remove_selected() {
            Some(series) => series,
            None => return Err(anyhow!("must select series to delete")),
        };

        // Since we changed our selected series, we need to make sure the new one is initialized
        self.init_selected_series();

        series.config().delete(&self.db)?;
        Ok(series)
    }

    async fn start_next_series_episode(state: &mut UIState) -> Result<(Child, ProgressTime)> {
        let series = match state.series.valid_selection_mut() {
            Some(series) => series,
            None => return Err(anyhow!("no series selected")),
        };

        let is_diff_series = state.last_watched.set(&series.data.config.nickname);

        if is_diff_series {
            state
                .last_watched
                .save()
                .context("setting last watched series")?;
        }

        let remote = state.remote.get_logged_in()?;

        series
            .begin_watching(remote, &state.config, &state.db)
            .context("updating series status")?;

        let next_ep = series.data.entry.watched_episodes() + 1;

        let child = series
            .play_episode(next_ep as u32, &state.config)
            .context("playing episode")?;

        let progress_time = series.data.next_watch_progress_time(&state.config);

        Ok((child, progress_time))
    }

    pub async fn play_next_series_episode(&mut self, shared_state: &SharedState) -> Result<()> {
        let (ep_process, progress_time) = Self::start_next_series_episode(self).await?;

        self.events
            .send(StateEvent::StartedEpisode(progress_time))
            .ok();

        self.input_state = InputState::Locked;

        let shared_state = shared_state.clone();

        task::spawn(async move {
            let result = shared_state
                .track_episode_finish(ep_process, progress_time)
                .await;

            let mut state = shared_state.lock();
            let state = state.get_mut();

            if let Err(err) = result {
                state.log.push_error(&err);
            }

            state.input_state.reset();
            state.events.send(StateEvent::FinishedEpisode).ok();
        });

        Ok(())
    }
}

pub type ReactiveState = Reactive<UIState>;

#[derive(Clone)]
pub struct SharedState(ArcMutex<ReactiveState>);

impl SharedState {
    pub fn new(state: ReactiveState) -> Self {
        Self(arc_mutex(state))
    }

    pub fn login_to_remote_async(&self, login: RemoteLogin) {
        let shared_state = self.clone();

        task::spawn_blocking(move || match login {
            RemoteLogin::AniList(username, token) => {
                {
                    let mut state = shared_state.lock();
                    state.get_mut().remote = RemoteStatus::LoggingIn(username);
                }

                let auth = Auth::retrieve(token);
                let mut state = shared_state.lock();
                let state = state.get_mut();

                let remote = match auth {
                    Ok(auth) => {
                        let anilist = AniList::Authenticated(auth);
                        RemoteStatus::LoggedIn(anilist.into())
                    }
                    Err(err) => {
                        state.log.push_error(&err.into());
                        RemoteStatus::LoggedIn(Remote::offline())
                    }
                };

                state.remote = remote;
            }
        });
    }

    async fn track_episode_finish(
        &self,
        mut ep_process: Child,
        progress_time: ProgressTime,
    ) -> Result<()> {
        ep_process
            .wait()
            .await
            .context("waiting for episode to finish")?;

        let mut state = self.lock();
        let state = state.get_mut();

        state.input_state.reset();

        if Utc::now() < progress_time {
            return Ok(());
        }

        let series = if let Some(series) = state.series.valid_selection_mut() {
            series
        } else {
            return Ok(());
        };

        let remote = state.remote.get_logged_in()?;

        series
            .episode_completed(remote, &state.config, &state.db)
            .context("marking episode as completed")
    }

    #[inline(always)]
    pub fn lock(&self) -> MutexGuard<'_, ReactiveState> {
        self.0.lock()
    }
}

#[derive(Clone, Copy)]
pub enum InputState {
    Idle,
    Locked,
    FocusedOnMainPanel,
    EnteringCommand,
}

impl InputState {
    #[inline(always)]
    pub fn reset(&mut self) {
        *self = Self::default();
    }
}

impl Default for InputState {
    fn default() -> Self {
        Self::Idle
    }
}

impl PartialEq for InputState {
    fn eq(&self, other: &Self) -> bool {
        mem::discriminant(self) == mem::discriminant(other)
    }
}

pub type ProgressTime = DateTime<Utc>;

#[derive(Debug, Clone)]
pub enum StateEvent {
    StartedEpisode(ProgressTime),
    FinishedEpisode,
}

pub struct Reactive<T> {
    state: T,
    pub dirty: Arc<Notify>,
}

impl<T> Reactive<T> {
    pub const fn new(state: T, dirty: Arc<Notify>) -> Self {
        Self { state, dirty }
    }

    #[inline(always)]
    pub fn get(&self) -> &T {
        &self.state
    }

    pub fn get_mut(&mut self) -> &mut T {
        self.mark_dirty();
        &mut self.state
    }

    #[inline(always)]
    pub fn mark_dirty(&mut self) {
        self.dirty.notify_waiters()
    }
}

impl<T> Deref for Reactive<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        self.get()
    }
}

#[derive(Debug)]
pub enum UIEvent {
    Key(Key),
    StateChange,
    Resize,
}

pub enum UIErrorKind {
    ExitRequest,
    Other(anyhow::Error),
}

pub type UIEventError<T> = std::result::Result<T, UIErrorKind>;

pub struct UIEvents {
    reader: EventStream,
    resize_event_stream: Signal,
}

impl UIEvents {
    pub fn new() -> Result<Self> {
        let resize_event_stream =
            signal(SignalKind::window_change()).context("SIGWINCH signal capture failed")?;

        Ok(Self {
            reader: EventStream::new(),
            resize_event_stream,
        })
    }

    #[allow(clippy::mut_mut)]
    pub async fn next(&mut self, state_change: &Notify) -> UIEventError<Option<UIEvent>> {
        let state_change = state_change.notified().fuse();
        tokio::pin!(state_change);

        let window_resize = self.resize_event_stream.recv().fuse();
        tokio::pin!(window_resize);

        let mut next_event = self.reader.next().fuse();

        select! {
            _ = state_change => Ok(Some(UIEvent::StateChange)),
            _ = window_resize => Ok(Some(UIEvent::Resize)),
            event = next_event => match event {
                Some(Ok(Event::Key(key))) => Ok(Some(UIEvent::Key(Key::new(key)))),
                Some(Ok(_)) => Ok(None),
                Some(Err(err)) => Err(UIErrorKind::Other(err.into())),
                None => Err(UIErrorKind::ExitRequest),
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use libc::{c_void, c_int, c_char, c_double, c_ulong, c_uint};

#[repr(C)]
#[derive(Copy)]
#[allow(dead_code)]
#[allow(non_camel_case_types)]
pub enum op_stat_t {
    OP_STAT_UNKNOWN = 0,
    OP_STAT_OPERATIONAL,    // Operational           [+]
    OP_STAT_NONOP,          // Nonoperational        [-]
    OP_STAT_PARTIAL,        // Partially operational [P]
    OP_STAT_STDBY,          // Backup/Standby        [B]
    OP_STAT_SPARE,          // Spare                 [S]
    OP_STAT_EXTENDED,       // Extended Mission      [X]
}

#[repr(C)]
#[derive(Copy)]
#[allow(dead_code)]
#[allow(non_camel_case_types)]
pub enum orbit_type_t {
    ORBIT_TYPE_UNKNOWN = 0,
    ORBIT_TYPE_LEO,         // Low Earth orbit, up to 1200 km
    ORBIT_TYPE_ICO,         // Intermediate Circular Orbit, up to 1400 km
    ORBIT_TYPE_GEO,         // Geostationary
    ORBIT_TYPE_GSO,         // Geosynchronuous
    ORBIT_TYPE_MOLNIYA,
    ORBIT_TYPE_TUNDRA,
    ORBIT_TYPE_POLAR,
    ORBIT_TYPE_SUNSYNC,
    ORBIT_TYPE_DECAYED
}

#[repr(C)]
#[allow(dead_code)]
pub struct qth_t {
    pub name:       *const c_char,  // Name, eg. callsign
    pub loc:        *const c_char,  // Location, eg City, Country
    pub desc:       *const c_char,  // Short description
    pub lat:        c_double,       // Latitude in dec. deg. North
    pub lon:        c_double,       // Longitude in dec. deg. East
    pub alt:        c_int,          // Altitude above sea level in meters
    pub qra:        *const c_char,  // QRA locator
    pub wx:         *const c_char,  // Weather station code (4 chars)
}

#[repr(C)]
#[allow(dead_code)]
pub struct tle_t {
    pub epoch:      c_double,       // Epoch Time in NORAD TLE format YYDDD.FFFFFFFF
    pub epoch_year: c_uint,         // Epoch: year
    pub epoch_day:  c_uint,         // Epoch: day of year
    pub epoch_fod:  c_double,       // Epoch: Fraction of day
    pub xndt2o:     c_double,       // 1. time derivative of mean motion
    pub xndd6o:     c_double,       // 2. time derivative of mean motion
    pub bstar:      c_double,       // Bstar drag coefficient
    pub xincl:      c_double,       // Inclination
    pub xnodeo:     c_double,       // R.A.A.N.
    pub eo:         c_double,       // Eccentricity
    pub omegao:     c_double,       // argument of perigee
    pub xmo:        c_double,       // mean anomaly
    pub xno:        c_double,       // mean motion

    pub catnr:      c_int,          // Catalogue Number
    pub elset:      c_int,          // Element Set number
    pub revnum:     c_int,          // Revolution Number at epoch

    pub sat_name:   [c_char; 25],   // Satellite name string
    pub idesg:      [c_char; 9],    // International Designator
    pub status:     op_stat_t,      // Operational status

    // values needed for squint calculations
    pub xincl1:     c_double,
    pub xnodeo1:    c_double,
    pub omegao1:    c_double,
}

#[repr(C)]
#[derive(Default)]
#[allow(dead_code)]
pub struct vector_t {
    pub x:          c_double,   // X component
    pub y:          c_double,   // Y component
    pub z:          c_double,   // Z component
    pub w:          c_double,   // Magnitude
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Default)]
/// Common arguments between deep-space functions
pub struct deep_arg_t {
    // Used by dpinit part of Deep()
    pub eosq:       c_double,
    pub sinio:      c_double,
    pub cosio:      c_double,
    pub betao:      c_double,
    pub aodp:       c_double,
    pub theta2:     c_double,
    pub sing:       c_double,
    pub cosg:       c_double,
    pub betao2:     c_double,
    pub xmdot:      c_double,
    pub omgdot:     c_double,
    pub xnodot:     c_double,
    pub xnodp:      c_double,

    // Used by dpsec and dpper parts of Deep()
    pub xll:        c_double,
    pub omgadf:     c_double,
    pub xnode:      c_double,
    pub em:         c_double,
    pub xinc:       c_double,
    pub xn:         c_double,
    pub t:          c_double,

    // Used by thetg and Deep()
    pub ds50:       c_double,
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Default)]
/// static data for SGP4 and SDP4
pub struct sgpsdp_static_t {
    pub aodp:       c_double,
    pub aycof:      c_double,
    pub c1:         c_double,
    pub c4:         c_double,
    pub c5:         c_double,
    pub cosio:      c_double,
    pub d2:         c_double,
    pub d3:         c_double,
    pub d4:         c_double,
    pub delmo:      c_double,
    pub omgcof:     c_double,

    pub eta:        c_double,
    pub omgdot:     c_double,
    pub sinio:      c_double,
    pub xnodp:      c_double,
    pub sinmo:      c_double,
    pub t2cof:      c_double,
    pub t3cof:      c_double,
    pub t4cof:      c_double,
    pub t5cof:      c_double,

    pub x1mth2:     c_double,
    pub x3thm1:     c_double,
    pub x7thm1:     c_double,
    pub xmcof:      c_double,
    pub xmdot:      c_double,
    pub xnodcf:     c_double,
    pub xnodot:     c_double,
    pub xlcof:      c_double,
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Default)]
/// static data for DEEP
pub struct deep_static_t {
    pub thgr:       c_double,
    pub xnq:        c_double,
    pub xqncl:      c_double,
    pub omegaq:     c_double,
    pub zmol:       c_double,
    pub zmos:       c_double,
    pub savtsn:     c_double,
    pub ee2:        c_double,
    pub e3:         c_double,
    pub xi2:        c_double,

    pub xl2:        c_double,
    pub xl3:        c_double,
    pub xl4:        c_double,
    pub xgh2:       c_double,
    pub xgh3:       c_double,
    pub xgh4:       c_double,
    pub xh2:        c_double,
    pub xh3:        c_double,
    pub sse:        c_double,
    pub ssi:        c_double,
    pub ssg:        c_double,
    pub xi3:        c_double,

    pub se2:        c_double,
    pub si2:        c_double,
    pub sl2:        c_double,
    pub sgh2:       c_double,
    pub sh2:        c_double,
    pub se3:        c_double,
    pub si3:        c_double,
    pub sl3:        c_double,
    pub sgh3:       c_double,
    pub sh3:        c_double,
    pub sl4:        c_double,
    pub sgh4:       c_double,

    pub ssl:        c_double,
    pub ssh:        c_double,
    pub d3210:      c_double,
    pub d3222:      c_double,
    pub d4410:      c_double,
    pub d4422:      c_double,
    pub d5220:      c_double,
    pub d5232:      c_double,
    pub d5421:      c_double,

    pub d5433:      c_double,
    pub del1:       c_double,
    pub del2:       c_double,
    pub del3:       c_double,
    pub fasx2:      c_double,
    pub fasx4:      c_double,
    pub fasx6:      c_double,
    pub xlamo:      c_double,
    pub xfact:      c_double,

    pub xni:        c_double,
    pub atime:      c_double,
    pub stepp:      c_double,
    pub stepn:      c_double,
    pub step2:      c_double,
    pub preep:      c_double,
    pub pl:         c_double,
    pub sghs:       c_double,
    pub xli:        c_double,

    pub d2201:      c_double,
    pub d2211:      c_double,
    pub sghl:       c_double,
    pub sh1:        c_double,
    pub pinc:       c_double,
    pub pe:         c_double,
    pub shs:        c_double,
    pub zsingl:     c_double,
    pub zcosgl:     c_double,

    pub zsinhl:     c_double,
    pub zcoshl:     c_double,
    pub zsinil:     c_double,
    pub zcosil:     c_double,

}

#[repr(C)]
pub struct sat_t {
    pub name:       *const c_char,
    pub nickname:   *const c_char,
    pub website:    *const c_char,
    pub tle:        tle_t,          // Keplerian elements
    pub flags:      c_int,          // Flags for algo ctrl
    pub sgps:       sgpsdp_static_t,
    pub dps:        deep_static_t,
    pub deep_arg:   deep_arg_t,
    pub pos:        vector_t,       // Raw position and range
    pub vel:        vector_t,       // Raw velocity

    pub jul_epoch:  c_double,
    pub jul_utc:    c_double,
    pub tsince:     c_double,
    pub aos:        c_double,       // Next AOS
    pub los:        c_double,       // Next LO

    pub az:         c_double,       // Azimuth [deg]
    pub el:         c_double,       // Elevation [deg]
    pub range:      c_double,       // Range [km]
    pub range_rate: c_double,       // Range Rate [km/sec]
    pub ra:         c_double,       // Right Ascension [deg]
    pub dec:        c_double,       // Declination [deg]
    pub ssplat:     c_double,       // SSP latitude [deg]
    pub ssplon:     c_double,       // SSP longitude [deg]
    pub alt:        c_double,       // altitude [km]
    pub velo:       c_double,       // velocity [km/s]
    pub ma:         c_double,       // mean anomaly
    pub footprint:  c_double,       // footprint
    pub phase:      c_double,       // orbit phase
    pub meanmo:     c_double,       // mean motion kept in rev/day
    pub orbit:      c_ulong,        // orbit number
    pub otype:      orbit_type_t    // orbit type
}

#[link(name = "gpredict")]
extern {
    pub fn get_current_daynum() -> c_double;
    pub fn predict_calc(sat: *mut sat_t, qth: *mut qth_t, t: c_double) -> c_void;

    pub fn Get_Next_Tle_Set(line: *const c_char, tle: *mut tle_t) -> c_int;
    pub fn select_ephemeris(sat: *mut sat_t) -> c_void;
    pub fn gtk_sat_data_init_sat(sat: *mut sat_t, sat: *mut qth_t) -> c_void;
}
<commit_msg>remove #[derive(Copy)] from ffipredict.rs enums<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use libc::{c_void, c_int, c_char, c_double, c_ulong, c_uint};

#[repr(C)]
#[allow(dead_code)]
#[allow(non_camel_case_types)]
pub enum op_stat_t {
    OP_STAT_UNKNOWN = 0,
    OP_STAT_OPERATIONAL,    // Operational           [+]
    OP_STAT_NONOP,          // Nonoperational        [-]
    OP_STAT_PARTIAL,        // Partially operational [P]
    OP_STAT_STDBY,          // Backup/Standby        [B]
    OP_STAT_SPARE,          // Spare                 [S]
    OP_STAT_EXTENDED,       // Extended Mission      [X]
}

#[repr(C)]
#[allow(dead_code)]
#[allow(non_camel_case_types)]
pub enum orbit_type_t {
    ORBIT_TYPE_UNKNOWN = 0,
    ORBIT_TYPE_LEO,         // Low Earth orbit, up to 1200 km
    ORBIT_TYPE_ICO,         // Intermediate Circular Orbit, up to 1400 km
    ORBIT_TYPE_GEO,         // Geostationary
    ORBIT_TYPE_GSO,         // Geosynchronuous
    ORBIT_TYPE_MOLNIYA,
    ORBIT_TYPE_TUNDRA,
    ORBIT_TYPE_POLAR,
    ORBIT_TYPE_SUNSYNC,
    ORBIT_TYPE_DECAYED
}

#[repr(C)]
#[allow(dead_code)]
pub struct qth_t {
    pub name:       *const c_char,  // Name, eg. callsign
    pub loc:        *const c_char,  // Location, eg City, Country
    pub desc:       *const c_char,  // Short description
    pub lat:        c_double,       // Latitude in dec. deg. North
    pub lon:        c_double,       // Longitude in dec. deg. East
    pub alt:        c_int,          // Altitude above sea level in meters
    pub qra:        *const c_char,  // QRA locator
    pub wx:         *const c_char,  // Weather station code (4 chars)
}

#[repr(C)]
#[allow(dead_code)]
pub struct tle_t {
    pub epoch:      c_double,       // Epoch Time in NORAD TLE format YYDDD.FFFFFFFF
    pub epoch_year: c_uint,         // Epoch: year
    pub epoch_day:  c_uint,         // Epoch: day of year
    pub epoch_fod:  c_double,       // Epoch: Fraction of day
    pub xndt2o:     c_double,       // 1. time derivative of mean motion
    pub xndd6o:     c_double,       // 2. time derivative of mean motion
    pub bstar:      c_double,       // Bstar drag coefficient
    pub xincl:      c_double,       // Inclination
    pub xnodeo:     c_double,       // R.A.A.N.
    pub eo:         c_double,       // Eccentricity
    pub omegao:     c_double,       // argument of perigee
    pub xmo:        c_double,       // mean anomaly
    pub xno:        c_double,       // mean motion

    pub catnr:      c_int,          // Catalogue Number
    pub elset:      c_int,          // Element Set number
    pub revnum:     c_int,          // Revolution Number at epoch

    pub sat_name:   [c_char; 25],   // Satellite name string
    pub idesg:      [c_char; 9],    // International Designator
    pub status:     op_stat_t,      // Operational status

    // values needed for squint calculations
    pub xincl1:     c_double,
    pub xnodeo1:    c_double,
    pub omegao1:    c_double,
}

#[repr(C)]
#[derive(Default)]
#[allow(dead_code)]
pub struct vector_t {
    pub x:          c_double,   // X component
    pub y:          c_double,   // Y component
    pub z:          c_double,   // Z component
    pub w:          c_double,   // Magnitude
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Default)]
/// Common arguments between deep-space functions
pub struct deep_arg_t {
    // Used by dpinit part of Deep()
    pub eosq:       c_double,
    pub sinio:      c_double,
    pub cosio:      c_double,
    pub betao:      c_double,
    pub aodp:       c_double,
    pub theta2:     c_double,
    pub sing:       c_double,
    pub cosg:       c_double,
    pub betao2:     c_double,
    pub xmdot:      c_double,
    pub omgdot:     c_double,
    pub xnodot:     c_double,
    pub xnodp:      c_double,

    // Used by dpsec and dpper parts of Deep()
    pub xll:        c_double,
    pub omgadf:     c_double,
    pub xnode:      c_double,
    pub em:         c_double,
    pub xinc:       c_double,
    pub xn:         c_double,
    pub t:          c_double,

    // Used by thetg and Deep()
    pub ds50:       c_double,
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Default)]
/// static data for SGP4 and SDP4
pub struct sgpsdp_static_t {
    pub aodp:       c_double,
    pub aycof:      c_double,
    pub c1:         c_double,
    pub c4:         c_double,
    pub c5:         c_double,
    pub cosio:      c_double,
    pub d2:         c_double,
    pub d3:         c_double,
    pub d4:         c_double,
    pub delmo:      c_double,
    pub omgcof:     c_double,

    pub eta:        c_double,
    pub omgdot:     c_double,
    pub sinio:      c_double,
    pub xnodp:      c_double,
    pub sinmo:      c_double,
    pub t2cof:      c_double,
    pub t3cof:      c_double,
    pub t4cof:      c_double,
    pub t5cof:      c_double,

    pub x1mth2:     c_double,
    pub x3thm1:     c_double,
    pub x7thm1:     c_double,
    pub xmcof:      c_double,
    pub xmdot:      c_double,
    pub xnodcf:     c_double,
    pub xnodot:     c_double,
    pub xlcof:      c_double,
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Default)]
/// static data for DEEP
pub struct deep_static_t {
    pub thgr:       c_double,
    pub xnq:        c_double,
    pub xqncl:      c_double,
    pub omegaq:     c_double,
    pub zmol:       c_double,
    pub zmos:       c_double,
    pub savtsn:     c_double,
    pub ee2:        c_double,
    pub e3:         c_double,
    pub xi2:        c_double,

    pub xl2:        c_double,
    pub xl3:        c_double,
    pub xl4:        c_double,
    pub xgh2:       c_double,
    pub xgh3:       c_double,
    pub xgh4:       c_double,
    pub xh2:        c_double,
    pub xh3:        c_double,
    pub sse:        c_double,
    pub ssi:        c_double,
    pub ssg:        c_double,
    pub xi3:        c_double,

    pub se2:        c_double,
    pub si2:        c_double,
    pub sl2:        c_double,
    pub sgh2:       c_double,
    pub sh2:        c_double,
    pub se3:        c_double,
    pub si3:        c_double,
    pub sl3:        c_double,
    pub sgh3:       c_double,
    pub sh3:        c_double,
    pub sl4:        c_double,
    pub sgh4:       c_double,

    pub ssl:        c_double,
    pub ssh:        c_double,
    pub d3210:      c_double,
    pub d3222:      c_double,
    pub d4410:      c_double,
    pub d4422:      c_double,
    pub d5220:      c_double,
    pub d5232:      c_double,
    pub d5421:      c_double,

    pub d5433:      c_double,
    pub del1:       c_double,
    pub del2:       c_double,
    pub del3:       c_double,
    pub fasx2:      c_double,
    pub fasx4:      c_double,
    pub fasx6:      c_double,
    pub xlamo:      c_double,
    pub xfact:      c_double,

    pub xni:        c_double,
    pub atime:      c_double,
    pub stepp:      c_double,
    pub stepn:      c_double,
    pub step2:      c_double,
    pub preep:      c_double,
    pub pl:         c_double,
    pub sghs:       c_double,
    pub xli:        c_double,

    pub d2201:      c_double,
    pub d2211:      c_double,
    pub sghl:       c_double,
    pub sh1:        c_double,
    pub pinc:       c_double,
    pub pe:         c_double,
    pub shs:        c_double,
    pub zsingl:     c_double,
    pub zcosgl:     c_double,

    pub zsinhl:     c_double,
    pub zcoshl:     c_double,
    pub zsinil:     c_double,
    pub zcosil:     c_double,

}

#[repr(C)]
pub struct sat_t {
    pub name:       *const c_char,
    pub nickname:   *const c_char,
    pub website:    *const c_char,
    pub tle:        tle_t,          // Keplerian elements
    pub flags:      c_int,          // Flags for algo ctrl
    pub sgps:       sgpsdp_static_t,
    pub dps:        deep_static_t,
    pub deep_arg:   deep_arg_t,
    pub pos:        vector_t,       // Raw position and range
    pub vel:        vector_t,       // Raw velocity

    pub jul_epoch:  c_double,
    pub jul_utc:    c_double,
    pub tsince:     c_double,
    pub aos:        c_double,       // Next AOS
    pub los:        c_double,       // Next LO

    pub az:         c_double,       // Azimuth [deg]
    pub el:         c_double,       // Elevation [deg]
    pub range:      c_double,       // Range [km]
    pub range_rate: c_double,       // Range Rate [km/sec]
    pub ra:         c_double,       // Right Ascension [deg]
    pub dec:        c_double,       // Declination [deg]
    pub ssplat:     c_double,       // SSP latitude [deg]
    pub ssplon:     c_double,       // SSP longitude [deg]
    pub alt:        c_double,       // altitude [km]
    pub velo:       c_double,       // velocity [km/s]
    pub ma:         c_double,       // mean anomaly
    pub footprint:  c_double,       // footprint
    pub phase:      c_double,       // orbit phase
    pub meanmo:     c_double,       // mean motion kept in rev/day
    pub orbit:      c_ulong,        // orbit number
    pub otype:      orbit_type_t    // orbit type
}

#[link(name = "gpredict")]
extern {
    pub fn get_current_daynum() -> c_double;
    pub fn predict_calc(sat: *mut sat_t, qth: *mut qth_t, t: c_double) -> c_void;

    pub fn Get_Next_Tle_Set(line: *const c_char, tle: *mut tle_t) -> c_int;
    pub fn select_ephemeris(sat: *mut sat_t) -> c_void;
    pub fn gtk_sat_data_init_sat(sat: *mut sat_t, sat: *mut qth_t) -> c_void;
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    access_path::AccessPath, account_address::AccountAddress,
    proto::language_storage::ModuleId as ProtoModuleId,
};
use canonical_serialization::{
    CanonicalDeserialize, CanonicalDeserializer, CanonicalSerialize, CanonicalSerializer,
    SimpleSerializer,
};
use crypto::hash::{AccessPathHasher, CryptoHash, CryptoHasher, HashValue};
use failure::Result;
use proptest_derive::Arbitrary;
use proto_conv::{FromProto, IntoProto};
use serde::{Deserialize, Serialize};
use std::string::String;

#[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord)]
pub struct StructTag {
    pub address: AccountAddress,
    pub module: String,
    pub name: String,
    pub type_params: Vec<StructTag>,
}

/// Represents the intitial key into global storage where we first index by the address, and then
/// the struct tag
#[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord)]
pub struct ResourceKey {
    address: AccountAddress,
    type_: StructTag,
}

impl ResourceKey {
    pub fn address(&self) -> AccountAddress {
        self.address
    }

    pub fn type_(&self) -> &StructTag {
        &self.type_
    }
}

impl ResourceKey {
    pub fn new(address: AccountAddress, type_: StructTag) -> Self {
        ResourceKey { address, type_ }
    }
}

/// Represents the initial key into global storage where we first index by the address, and then
/// the struct tag
#[derive(
    Serialize,
    Deserialize,
    Debug,
    PartialEq,
    Hash,
    Eq,
    Clone,
    PartialOrd,
    Ord,
    FromProto,
    IntoProto,
    Arbitrary,
)]
#[ProtoType(ProtoModuleId)]
#[proptest(no_params)]
pub struct ModuleId {
    address: AccountAddress,
    name: String,
}

impl ModuleId {
    pub fn new(address: AccountAddress, name: String) -> Self {
        ModuleId { address, name }
    }

    pub fn name(&self) -> &String {
        &self.name
    }

    pub fn address(&self) -> &AccountAddress {
        &self.address
    }
}

impl<'a> Into<AccessPath> for &'a ModuleId {
    fn into(self) -> AccessPath {
        AccessPath::code_access_path(self)
    }
}

impl CanonicalSerialize for ModuleId {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> Result<()> {
        serializer
            .encode_struct(&self.address)?
            .encode_variable_length_bytes(self.name.as_bytes())?;
        Ok(())
    }
}

impl CanonicalDeserialize for ModuleId {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        let address = deserializer.decode_struct::<AccountAddress>()?;
        let name = String::from_utf8(deserializer.decode_variable_length_bytes()?)?;

        Ok(Self { address, name })
    }
}

impl CryptoHash for ModuleId {
    type Hasher = AccessPathHasher;

    fn hash(&self) -> HashValue {
        let mut state = Self::Hasher::default();
        state.write(&SimpleSerializer::<Vec<u8>>::serialize(self).unwrap());
        state.finish()
    }
}

impl CanonicalSerialize for StructTag {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> Result<()> {
        serializer
            .encode_struct(&self.address)?
            .encode_variable_length_bytes(self.module.as_bytes())?
            .encode_variable_length_bytes(self.name.as_bytes())?
            .encode_vec(&self.type_params)?;
        Ok(())
    }
}

impl CanonicalDeserialize for StructTag {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        let address = deserializer.decode_struct::<AccountAddress>()?;
        let module = String::from_utf8(deserializer.decode_variable_length_bytes()?)?;
        let name = String::from_utf8(deserializer.decode_variable_length_bytes()?)?;
        let type_params = deserializer.decode_vec::<StructTag>()?;
        Ok(Self {
            address,
            name,
            module,
            type_params,
        })
    }
}

impl CryptoHash for StructTag {
    type Hasher = AccessPathHasher;

    fn hash(&self) -> HashValue {
        let mut state = Self::Hasher::default();
        state.write(&SimpleSerializer::<Vec<u8>>::serialize(self).unwrap());
        state.finish()
    }
}
<commit_msg>[types] impl From instead of Into for module ID to access path conversion<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    access_path::AccessPath, account_address::AccountAddress,
    proto::language_storage::ModuleId as ProtoModuleId,
};
use canonical_serialization::{
    CanonicalDeserialize, CanonicalDeserializer, CanonicalSerialize, CanonicalSerializer,
    SimpleSerializer,
};
use crypto::hash::{AccessPathHasher, CryptoHash, CryptoHasher, HashValue};
use failure::Result;
use proptest_derive::Arbitrary;
use proto_conv::{FromProto, IntoProto};
use serde::{Deserialize, Serialize};
use std::string::String;

#[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord)]
pub struct StructTag {
    pub address: AccountAddress,
    pub module: String,
    pub name: String,
    pub type_params: Vec<StructTag>,
}

/// Represents the intitial key into global storage where we first index by the address, and then
/// the struct tag
#[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord)]
pub struct ResourceKey {
    address: AccountAddress,
    type_: StructTag,
}

impl ResourceKey {
    pub fn address(&self) -> AccountAddress {
        self.address
    }

    pub fn type_(&self) -> &StructTag {
        &self.type_
    }
}

impl ResourceKey {
    pub fn new(address: AccountAddress, type_: StructTag) -> Self {
        ResourceKey { address, type_ }
    }
}

/// Represents the initial key into global storage where we first index by the address, and then
/// the struct tag
#[derive(
    Serialize,
    Deserialize,
    Debug,
    PartialEq,
    Hash,
    Eq,
    Clone,
    PartialOrd,
    Ord,
    FromProto,
    IntoProto,
    Arbitrary,
)]
#[ProtoType(ProtoModuleId)]
#[proptest(no_params)]
pub struct ModuleId {
    address: AccountAddress,
    name: String,
}

impl ModuleId {
    pub fn new(address: AccountAddress, name: String) -> Self {
        ModuleId { address, name }
    }

    pub fn name(&self) -> &String {
        &self.name
    }

    pub fn address(&self) -> &AccountAddress {
        &self.address
    }
}

impl<'a> From<&'a ModuleId> for AccessPath {
    fn from(module_id: &'a ModuleId) -> Self {
        AccessPath::code_access_path(module_id)
    }
}

impl CanonicalSerialize for ModuleId {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> Result<()> {
        serializer
            .encode_struct(&self.address)?
            .encode_variable_length_bytes(self.name.as_bytes())?;
        Ok(())
    }
}

impl CanonicalDeserialize for ModuleId {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        let address = deserializer.decode_struct::<AccountAddress>()?;
        let name = String::from_utf8(deserializer.decode_variable_length_bytes()?)?;

        Ok(Self { address, name })
    }
}

impl CryptoHash for ModuleId {
    type Hasher = AccessPathHasher;

    fn hash(&self) -> HashValue {
        let mut state = Self::Hasher::default();
        state.write(&SimpleSerializer::<Vec<u8>>::serialize(self).unwrap());
        state.finish()
    }
}

impl CanonicalSerialize for StructTag {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> Result<()> {
        serializer
            .encode_struct(&self.address)?
            .encode_variable_length_bytes(self.module.as_bytes())?
            .encode_variable_length_bytes(self.name.as_bytes())?
            .encode_vec(&self.type_params)?;
        Ok(())
    }
}

impl CanonicalDeserialize for StructTag {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        let address = deserializer.decode_struct::<AccountAddress>()?;
        let module = String::from_utf8(deserializer.decode_variable_length_bytes()?)?;
        let name = String::from_utf8(deserializer.decode_variable_length_bytes()?)?;
        let type_params = deserializer.decode_vec::<StructTag>()?;
        Ok(Self {
            address,
            name,
            module,
            type_params,
        })
    }
}

impl CryptoHash for StructTag {
    type Hasher = AccessPathHasher;

    fn hash(&self) -> HashValue {
        let mut state = Self::Hasher::default();
        state.write(&SimpleSerializer::<Vec<u8>>::serialize(self).unwrap());
        state.finish()
    }
}
<|endoftext|>


<commit_before>use ra_ide_db::defs::{classify_name_ref, Definition, NameRefClass};
use ra_syntax::{ast, AstNode, SyntaxKind, T};
use test_utils::mark;

use crate::{
    assist_context::{AssistContext, Assists},
    AssistId, AssistKind,
};

// Assist: add_turbo_fish
//
// Adds `::<_>` to a call of a generic method or function.
//
// ```
// fn make<T>() -> T { todo!() }
// fn main() {
//     let x = make<|>();
// }
// ```
// ->
// ```
// fn make<T>() -> T { todo!() }
// fn main() {
//     let x = make::<${0:_}>();
// }
// ```
pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let ident = ctx.find_token_at_offset(SyntaxKind::IDENT)?;
    let next_token = ident.next_token()?;
    if next_token.kind() == T![::] {
        mark::hit!(add_turbo_fish_one_fish_is_enough);
        return None;
    }
    let name_ref = ast::NameRef::cast(ident.parent())?;
    let def = match classify_name_ref(&ctx.sema, &name_ref)? {
        NameRefClass::Definition(def) => def,
        NameRefClass::FieldShorthand { .. } => return None,
    };
    let fun = match def {
        Definition::ModuleDef(hir::ModuleDef::Function(it)) => it,
        _ => return None,
    };
    let generics = hir::GenericDef::Function(fun).params(ctx.sema.db);
    if generics.is_empty() {
        mark::hit!(add_turbo_fish_non_generic);
        return None;
    }
    acc.add(
        AssistId("add_turbo_fish", AssistKind::RefactorRewrite),
        "Add `::<>`",
        ident.text_range(),
        |builder| match ctx.config.snippet_cap {
            Some(cap) => builder.insert_snippet(cap, ident.text_range().end(), "::<${0:_}>"),
            None => builder.insert(ident.text_range().end(), "::<_>"),
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;
    use test_utils::mark;

    #[test]
    fn add_turbo_fish_function() {
        check_assist(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    make<|>();
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    make::<${0:_}>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_method() {
        check_assist(
            add_turbo_fish,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    S.make<|>();
}
"#,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    S.make::<${0:_}>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_one_fish_is_enough() {
        mark::check!(add_turbo_fish_one_fish_is_enough);
        check_assist_not_applicable(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    make<|>::<()>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_non_generic() {
        mark::check!(add_turbo_fish_non_generic);
        check_assist_not_applicable(
            add_turbo_fish,
            r#"
fn make() -> () {}
fn main() {
    make<|>();
}
"#,
        );
    }
}
<commit_msg>Add turbo-fish works after `()`<commit_after>use ra_ide_db::defs::{classify_name_ref, Definition, NameRefClass};
use ra_syntax::{ast, AstNode, SyntaxKind, T};
use test_utils::mark;

use crate::{
    assist_context::{AssistContext, Assists},
    AssistId, AssistKind,
};

// Assist: add_turbo_fish
//
// Adds `::<_>` to a call of a generic method or function.
//
// ```
// fn make<T>() -> T { todo!() }
// fn main() {
//     let x = make<|>();
// }
// ```
// ->
// ```
// fn make<T>() -> T { todo!() }
// fn main() {
//     let x = make::<${0:_}>();
// }
// ```
pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let ident = ctx.find_token_at_offset(SyntaxKind::IDENT).or_else(|| {
        let arg_list = ctx.find_node_at_offset::<ast::ArgList>()?;
        if arg_list.args().count() > 0 {
            return None;
        }
        mark::hit!(add_turbo_fish_after_call);
        arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT)
    })?;
    let next_token = ident.next_token()?;
    if next_token.kind() == T![::] {
        mark::hit!(add_turbo_fish_one_fish_is_enough);
        return None;
    }
    let name_ref = ast::NameRef::cast(ident.parent())?;
    let def = match classify_name_ref(&ctx.sema, &name_ref)? {
        NameRefClass::Definition(def) => def,
        NameRefClass::FieldShorthand { .. } => return None,
    };
    let fun = match def {
        Definition::ModuleDef(hir::ModuleDef::Function(it)) => it,
        _ => return None,
    };
    let generics = hir::GenericDef::Function(fun).params(ctx.sema.db);
    if generics.is_empty() {
        mark::hit!(add_turbo_fish_non_generic);
        return None;
    }
    acc.add(
        AssistId("add_turbo_fish", AssistKind::RefactorRewrite),
        "Add `::<>`",
        ident.text_range(),
        |builder| match ctx.config.snippet_cap {
            Some(cap) => builder.insert_snippet(cap, ident.text_range().end(), "::<${0:_}>"),
            None => builder.insert(ident.text_range().end(), "::<_>"),
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;
    use test_utils::mark;

    #[test]
    fn add_turbo_fish_function() {
        check_assist(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    make<|>();
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    make::<${0:_}>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_after_call() {
        mark::check!(add_turbo_fish_after_call);
        check_assist(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    make()<|>;
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    make::<${0:_}>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_method() {
        check_assist(
            add_turbo_fish,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    S.make<|>();
}
"#,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    S.make::<${0:_}>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_one_fish_is_enough() {
        mark::check!(add_turbo_fish_one_fish_is_enough);
        check_assist_not_applicable(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    make<|>::<()>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_non_generic() {
        mark::check!(add_turbo_fish_non_generic);
        check_assist_not_applicable(
            add_turbo_fish,
            r#"
fn make() -> () {}
fn main() {
    make<|>();
}
"#,
        );
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use crossbeam_utils::sync::WaitGroup;

const THREADS: usize = 10;

#[test]
fn wait() {
    let wg = WaitGroup::new();
    let (tx, rx) = mpsc::channel();

    for _ in 0..THREADS {
        let wg = wg.clone();
        let tx = tx.clone();

        thread::spawn(move || {
            wg.wait();
            tx.send(()).unwrap();
        });
    }

    thread::sleep(Duration::from_millis(100));

    // At this point, all spawned threads should be blocked, so we shouldn't get anything from the
    // channel.
    assert!(rx.try_recv().is_err());

    wg.wait();

    // Now, the wait group is cleared and we should receive messages.
    for _ in 0..THREADS {
        rx.recv().unwrap();
    }
}

#[test]
fn wait_and_drop() {
    let wg = WaitGroup::new();
    let (tx, rx) = mpsc::channel();

    for _ in 0..THREADS {
        let wg = wg.clone();
        let tx = tx.clone();

        thread::spawn(move || {
            thread::sleep(Duration::from_millis(100));
            tx.send(()).unwrap();
            drop(wg);
        });
    }

    // At this point, all spawned threads should be sleeping, so we shouldn't get anything from the
    // channel.
    assert!(rx.try_recv().is_err());

    wg.wait();

    // Now, the wait group is cleared and we should receive messages.
    for _ in 0..THREADS {
        rx.try_recv().unwrap();
    }
}
<commit_msg>do not run wait_and_drop in Miri<commit_after>use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use crossbeam_utils::sync::WaitGroup;

const THREADS: usize = 10;

#[test]
fn wait() {
    let wg = WaitGroup::new();
    let (tx, rx) = mpsc::channel();

    for _ in 0..THREADS {
        let wg = wg.clone();
        let tx = tx.clone();

        thread::spawn(move || {
            wg.wait();
            tx.send(()).unwrap();
        });
    }

    thread::sleep(Duration::from_millis(100));

    // At this point, all spawned threads should be blocked, so we shouldn't get anything from the
    // channel.
    assert!(rx.try_recv().is_err());

    wg.wait();

    // Now, the wait group is cleared and we should receive messages.
    for _ in 0..THREADS {
        rx.recv().unwrap();
    }
}

#[test]
#[cfg(not(miri))] // this test makes timing assumptions, but Miri is so slow it violates them
fn wait_and_drop() {
    let wg = WaitGroup::new();
    let (tx, rx) = mpsc::channel();

    for _ in 0..THREADS {
        let wg = wg.clone();
        let tx = tx.clone();

        thread::spawn(move || {
            thread::sleep(Duration::from_millis(100));
            tx.send(()).unwrap();
            drop(wg);
        });
    }

    // At this point, all spawned threads should be in `thread::sleep`, so we shouldn't get anything
    // from the channel.
    assert!(rx.try_recv().is_err());

    wg.wait();

    // Now, the wait group is cleared and we should receive messages.
    for _ in 0..THREADS {
        rx.try_recv().unwrap();
    }
}
<|endoftext|>


<commit_before>//! The Tessellated Intelligence System is a
//!
//! > massively parallel computer architecture comprised of non-uniformly
//! > interconnected heterogeneous nodes.
//!
//! The manual can be found [online](https://www.vidarholen.net/contents/junk/files/TIS-100%20Reference%20Manual.pdf).
//! Another useful resource is the unofficial [TIS-100 Hackers Guide](https://alandesmet.github.io/TIS-100-Hackers-Guide/).
//!
//! # Examples
//! Here we take a node and execute some instructions and check if double 1 has
//! the expected result.
//!
//! ```rust
//! extern crate tis_100_superoptimizer;
//!
//! use tis_100_superoptimizer::TIS_100::{Node,Instruction,Source,Destination,Register};
//!
//! fn main() {
//!     let node: Node = Node::new();
//!     let last: Node = node
//!         .execute(Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)))
//!         .execute(Instruction::ADD(Source::Register(Register::ACC)));
//!
//!     assert_eq!(2, last.acc);
//! }
//! ```

use std::fmt::{Debug,Formatter,Error};

/// A `Node` models the basic execution node in TIS-100. You change a node state
/// by executing an `Instruction` on it.
#[derive(Debug,PartialEq,Eq)]
pub struct Node {
    /// The accumulator for the basic execution node.
    pub acc: i32,
    bac: i32,
    pc: usize,
    program: Program,
}

/// A `Program` is a sequence of `Instruction`s
pub struct Program(pub Vec<Instruction>);

impl PartialEq for Program {
    fn eq(&self, other: &Program) -> bool {
        let Program(ref self_instructions) = *self;
        let Program(ref other_instructions) = *other;
        if self_instructions.len() == other_instructions.len() {
            for index in 0..(self_instructions.len()) {
                let ref self_instruction = self_instructions[index];
                let ref other_instruction = other_instructions[index];
                if self_instruction != other_instruction {
                    return false
                }
            }
            true
        } else {
            false
        }
    }
}

impl Eq for Program {}

impl Debug for Program {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let Program(ref instructions) = *self;
        write!(f, "[{}:", instructions.len()).unwrap();
        for instruction in instructions {
            write!(f, " {:?}", instruction).unwrap();
        }
        write!(f, "]")
    }
}

impl Clone for Program {
    fn clone(&self) -> Program {
        let mut clone_instructions: Vec<Instruction> = vec![];
        let Program(ref self_instructions) = *self;
        for ref mut instruction in self_instructions {
            clone_instructions.push(instruction.clone());
        }
        Program(clone_instructions)
    }
}

/// `Instruction`s are executed by a `Node`.
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Instruction {
    /// Does nothing
    NOP,
    /// Moves value from `Source` to `Destination`
    MOV(Source, Destination),
    /// Swaps the value of the accumulator (acc) and the backup (bac) register
    SWP,
    /// Saves the value of the accumulator (acc) to the backup register
    SAV,
    /// Add value from `Source` to accumulator (acc), storing result in acc
    ADD(Source),
    /// Subtracts value from `Source` from accumulator (acc), storing result in acc
    SUB(Source),
}

/// `Source` are either ports, registers or literals
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Source {
    /// A register
    Register(Register),
    /// A literal value
    Literal(i32)
}

/// Different types of Registers known in TIS-100
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Register {
    /// the NIL register, reading from it provides with zero
    NIL,
    /// The accumulator
    ACC,
}

/// `Destination` are either ports or registers
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Destination {
    /// A register
    Register(Register),
}

/// The `Status` a `Program` run on a certain `Node`.
pub enum Status {
    /// a successful run of the program
    Successful(Node),
    /// an unsuccessful run of the program, because of a deadlock.
    Deadlock(Node),
}

impl Node {
    /// Create a `Node` with defaults for accumulator, backup registers, program counter and program
    pub fn new() -> Node {
        Node { acc: 0, bac: 0, pc: 0, program: Program(vec![]) }
    }

    /// Loads a program in this `Node`
    pub fn load(&self, program: Program) -> Node {
        Node { program: program.clone(), .. *self }
    }

    /// Run the loaded program, returning an calculation state
    pub fn run(&self) -> Status {
        let mut node = Node { program: self.program.clone(), .. *self };

        loop {
            match node.fetch_instruction() {
                Some(instruction) => {
                    node = node.execute(instruction);
                }
                None => {
                    break
                }
            }
        }

        Status::Successful(Node { program: node.program.clone(), .. node })
    }

    fn fetch_instruction(&self) -> Option<Instruction> {
        let Program(ref instructions) = self.program;
        if self.pc < instructions.len() {
            Some(instructions[self.pc].clone())
        } else {
            None
        }
    }

    /// Create a `Node` from self with the program counter incremented
    fn increment_pc(&self) -> Node {
        Node { pc: self.pc + 1, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed program counter value
    fn set_pc(&self, pc: usize) -> Node {
        Node { pc: pc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed accumulator register value
    fn set_acc(&self, acc: i32) -> Node {
        Node { acc: acc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed backup register value
    fn set_bac(&self, bac: i32) -> Node {
        Node { bac: bac, program: self.program.clone(), .. *self }
    }

    /// Execute the `instruction` on this `Node`. Returns a `Node` that reflects
    /// the changes the `instruction` would have on this `Node`.
    pub fn execute(&self, instruction: Instruction) -> Node {
        match instruction {
            Instruction::NOP => self.nop(),
            Instruction::MOV(source, destination) => self.mov(source, destination) ,
            Instruction::SWP => self.swap(),
            Instruction::SAV => self.save(),
            Instruction::ADD(source) => self.add(source),
            Instruction::SUB(source) => self.subtract(source),
        }
    }

    fn nop(&self) -> Node {
        self.increment_pc()
    }

    fn mov(&self, source: Source, destination: Destination) -> Node {
        let value: i32 = self.value_from(source);

        self.move_value(value, destination)
    }

    fn value_from(&self, source: Source) -> i32 {
        match source {
            Source::Register(Register::NIL) => 0,
            Source::Register(Register::ACC) => self.acc,
            Source::Literal(value) => value,
        }
    }

    fn move_value(&self, value: i32, destination: Destination) -> Node {
        match destination {
            Destination::Register(Register::ACC) => self.increment_pc().set_acc(value),
            _ => self.nop(),
        }
    }

    fn swap(&self) -> Node {
        let acc: i32 = self.acc;
        let bac: i32 = self.bac;

        self.increment_pc().set_acc(bac).set_bac(acc)
    }

    fn save(&self) -> Node {
        self.increment_pc().set_bac(self.acc)
    }

    fn add(&self, source: Source) -> Node{
        let value: i32 = self.value_from(source);

        self.add_value(value)
    }

    fn add_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc + value)
    }

    fn subtract(&self, source: Source) -> Node {
        let value: i32 = self.value_from(source);

        self.subtract_value(value)
    }

    fn subtract_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc - value)
    }
}

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

    fn node_with(acc: i32, bac: i32, pc: usize) -> Node {
        Node::new().set_acc(acc).set_bac(bac).set_pc(pc)
    }

    #[test]
    fn node_should_start_with_accumulator_zero() {
        let node: Node = Node::new();

        assert_eq!(0, node.acc);
    }

    #[test]
    fn node_should_start_with_backup_zero() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(0, next.acc);
    }

    #[test]
    fn node_should_execute_NOP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::NOP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_NIL_to_NIL_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::NIL),
                                                        Destination::Register(Register::NIL));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_ACC_to_ACC_correctly() {
        let node: Node = Node::new().set_acc(2).set_bac(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::ACC),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 1, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_Literal_to_ACC_correctly() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::MOV(Source::Literal(1),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SWP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(0, 1, 1), next);
    }

    #[test]
    fn node_should_execute_SAV_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SAV;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 1, 1), next);
    }

    #[test]
    fn node_should_execute_ADD_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::ADD(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SUB_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(2);
        let instruction: Instruction = Instruction::SUB(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn programs_should_differ_when_different_size() {
        assert_eq!(false, Program(vec![]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_differ_when_different_instructions() {
        assert_eq!(false, Program(vec![Instruction::SWP]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_equal_with_same_instructions() {
        assert_eq!(Program(vec![Instruction::SAV]), Program(vec![Instruction::SAV]));
    }

    #[test]
    fn node_should_execute_program_correctly() {
        let program: Program = Program(vec![// calculate 4 * source - 1
            Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)),
            Instruction::ADD(Source::Register(Register::ACC)),
            Instruction::ADD(Source::Register(Register::ACC)),
            Instruction::SUB(Source::Literal(1))
        ]);
        let node: Node = Node::new().load(program);

        match node.run() {
            Status::Successful(_) => assert!(true),
            Status::Deadlock(_) => assert!(false),
        }
    }
}

<commit_msg>Correct some documentation<commit_after>//! The Tessellated Intelligence System is a
//!
//! > massively parallel computer architecture comprised of non-uniformly
//! > interconnected heterogeneous nodes.
//!
//! The manual can be found [online](https://www.vidarholen.net/contents/junk/files/TIS-100%20Reference%20Manual.pdf).
//! Another useful resource is the unofficial [TIS-100 Hackers Guide](https://alandesmet.github.io/TIS-100-Hackers-Guide/).
//!
//! # Examples
//! Here we take a node and execute some instructions and check if double 1 has
//! the expected result.
//!
//! ```rust
//! extern crate tis_100_superoptimizer;
//!
//! use tis_100_superoptimizer::TIS_100::{Node,Instruction,Source,Destination,Register};
//!
//! fn main() {
//!     let node: Node = Node::new();
//!     let last: Node = node
//!         .execute(Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)))
//!         .execute(Instruction::ADD(Source::Register(Register::ACC)));
//!
//!     assert_eq!(2, last.acc);
//! }
//! ```

use std::fmt::{Debug,Formatter,Error};

/// A `Node` models the basic execution node in TIS-100. You change a node state
/// by running `Program`s on it or executing an `Instruction` on it.
#[derive(Debug,PartialEq,Eq)]
pub struct Node {
    /// The accumulator for the basic execution node.
    pub acc: i32,
    bac: i32,
    pc: usize,
    program: Program,
}

/// A `Program` is a sequence of `Instruction`s
pub struct Program(pub Vec<Instruction>);

impl PartialEq for Program {
    fn eq(&self, other: &Program) -> bool {
        let Program(ref self_instructions) = *self;
        let Program(ref other_instructions) = *other;
        if self_instructions.len() == other_instructions.len() {
            for index in 0..(self_instructions.len()) {
                let ref self_instruction = self_instructions[index];
                let ref other_instruction = other_instructions[index];
                if self_instruction != other_instruction {
                    return false
                }
            }
            true
        } else {
            false
        }
    }
}

impl Eq for Program {}

impl Debug for Program {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let Program(ref instructions) = *self;
        write!(f, "[{}:", instructions.len()).unwrap();
        for instruction in instructions {
            write!(f, " {:?}", instruction).unwrap();
        }
        write!(f, "]")
    }
}

impl Clone for Program {
    fn clone(&self) -> Program {
        let mut clone_instructions: Vec<Instruction> = vec![];
        let Program(ref self_instructions) = *self;
        for ref mut instruction in self_instructions {
            clone_instructions.push(instruction.clone());
        }
        Program(clone_instructions)
    }
}

/// `Instruction`s are executed by a `Node`
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Instruction {
    /// Does nothing
    NOP,
    /// Moves value from `Source` to `Destination`
    MOV(Source, Destination),
    /// Swaps the value of the accumulator (acc) and the backup (bac) register
    SWP,
    /// Saves the value of the accumulator (acc) to the backup register
    SAV,
    /// Add value from `Source` to accumulator (acc), storing result in acc
    ADD(Source),
    /// Subtracts value from `Source` from accumulator (acc), storing result in acc
    SUB(Source),
}

/// `Source` are either ports, registers or literals
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Source {
    /// A register
    Register(Register),
    /// A literal value
    Literal(i32)
}

/// Different types of Registers known in TIS-100
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Register {
    /// the NIL register, reading from it provides with zero
    NIL,
    /// The accumulator
    ACC,
}

/// `Destination` are either ports or registers
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Destination {
    /// A register
    Register(Register),
}

/// The `Status` a `Program` run on a certain `Node`.
pub enum Status {
    /// a successful run of the program
    Successful(Node),
    /// an unsuccessful run of the program, because of a deadlock.
    Deadlock(Node),
}

impl Node {
    /// Create a `Node` with defaults for accumulator, backup registers, program counter and program
    pub fn new() -> Node {
        Node { acc: 0, bac: 0, pc: 0, program: Program(vec![]) }
    }

    /// Loads a program in this `Node`
    pub fn load(&self, program: Program) -> Node {
        Node { program: program.clone(), .. *self }
    }

    /// Run the loaded program, returning an calculation state
    pub fn run(&self) -> Status {
        let mut node = Node { program: self.program.clone(), .. *self };

        loop {
            match node.fetch_instruction() {
                Some(instruction) => {
                    node = node.execute(instruction);
                }
                None => {
                    break
                }
            }
        }

        Status::Successful(Node { program: node.program.clone(), .. node })
    }

    fn fetch_instruction(&self) -> Option<Instruction> {
        let Program(ref instructions) = self.program;
        if self.pc < instructions.len() {
            Some(instructions[self.pc].clone())
        } else {
            None
        }
    }

    /// Create a `Node` from self with the program counter incremented
    fn increment_pc(&self) -> Node {
        Node { pc: self.pc + 1, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed program counter value
    fn set_pc(&self, pc: usize) -> Node {
        Node { pc: pc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed accumulator register value
    fn set_acc(&self, acc: i32) -> Node {
        Node { acc: acc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed backup register value
    fn set_bac(&self, bac: i32) -> Node {
        Node { bac: bac, program: self.program.clone(), .. *self }
    }

    /// Execute the `instruction` on this `Node`. Returns a `Node` that reflects
    /// the changes the `instruction` would have on this `Node`.
    pub fn execute(&self, instruction: Instruction) -> Node {
        match instruction {
            Instruction::NOP => self.nop(),
            Instruction::MOV(source, destination) => self.mov(source, destination) ,
            Instruction::SWP => self.swap(),
            Instruction::SAV => self.save(),
            Instruction::ADD(source) => self.add(source),
            Instruction::SUB(source) => self.subtract(source),
        }
    }

    fn nop(&self) -> Node {
        self.increment_pc()
    }

    fn mov(&self, source: Source, destination: Destination) -> Node {
        let value: i32 = self.value_from(source);

        self.move_value(value, destination)
    }

    fn value_from(&self, source: Source) -> i32 {
        match source {
            Source::Register(Register::NIL) => 0,
            Source::Register(Register::ACC) => self.acc,
            Source::Literal(value) => value,
        }
    }

    fn move_value(&self, value: i32, destination: Destination) -> Node {
        match destination {
            Destination::Register(Register::ACC) => self.increment_pc().set_acc(value),
            _ => self.nop(),
        }
    }

    fn swap(&self) -> Node {
        let acc: i32 = self.acc;
        let bac: i32 = self.bac;

        self.increment_pc().set_acc(bac).set_bac(acc)
    }

    fn save(&self) -> Node {
        self.increment_pc().set_bac(self.acc)
    }

    fn add(&self, source: Source) -> Node{
        let value: i32 = self.value_from(source);

        self.add_value(value)
    }

    fn add_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc + value)
    }

    fn subtract(&self, source: Source) -> Node {
        let value: i32 = self.value_from(source);

        self.subtract_value(value)
    }

    fn subtract_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc - value)
    }
}

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

    fn node_with(acc: i32, bac: i32, pc: usize) -> Node {
        Node::new().set_acc(acc).set_bac(bac).set_pc(pc)
    }

    #[test]
    fn node_should_start_with_accumulator_zero() {
        let node: Node = Node::new();

        assert_eq!(0, node.acc);
    }

    #[test]
    fn node_should_start_with_backup_zero() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(0, next.acc);
    }

    #[test]
    fn node_should_execute_NOP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::NOP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_NIL_to_NIL_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::NIL),
                                                        Destination::Register(Register::NIL));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_ACC_to_ACC_correctly() {
        let node: Node = Node::new().set_acc(2).set_bac(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::ACC),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 1, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_Literal_to_ACC_correctly() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::MOV(Source::Literal(1),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SWP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(0, 1, 1), next);
    }

    #[test]
    fn node_should_execute_SAV_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SAV;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 1, 1), next);
    }

    #[test]
    fn node_should_execute_ADD_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::ADD(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SUB_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(2);
        let instruction: Instruction = Instruction::SUB(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn programs_should_differ_when_different_size() {
        assert_eq!(false, Program(vec![]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_differ_when_different_instructions() {
        assert_eq!(false, Program(vec![Instruction::SWP]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_equal_with_same_instructions() {
        assert_eq!(Program(vec![Instruction::SAV]), Program(vec![Instruction::SAV]));
    }

    #[test]
    fn node_should_execute_program_correctly() {
        let program: Program = Program(vec![// calculate 4 * source - 1
            Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)),
            Instruction::ADD(Source::Register(Register::ACC)),
            Instruction::ADD(Source::Register(Register::ACC)),
            Instruction::SUB(Source::Literal(1))
        ]);
        let node: Node = Node::new().load(program);

        match node.run() {
            Status::Successful(_) => assert!(true),
            Status::Deadlock(_) => assert!(false),
        }
    }
}

<|endoftext|>


<commit_before>///! fff-lang
///!
///! codemap/symbol_def
///! all kinds of strings, intern them to save memory and save copy time

use std::fmt;
use std::collections::HashMap;

#[derive(Eq, PartialEq, Clone, Copy, Hash)]
pub struct SymbolID(usize);
impl SymbolID { pub fn new(value: usize) -> SymbolID { SymbolID(value) } }
impl From<usize> for SymbolID { fn from(value: usize) -> SymbolID { SymbolID(value) } }
impl SymbolID {
    pub fn format(&self, symbols: Option<&SymbolCollection>) -> String {
        match symbols {
            None => format!("#{}", self.0),
            Some(symbols) => format!("{:?}", symbols.get(*self).unwrap_or("<no-sym>")),
        }
    }
}
impl fmt::Debug for SymbolID {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.format(None)) }
}

pub struct SymbolCollection {
    items: HashMap<String, SymbolID>,
}
impl fmt::Debug for SymbolCollection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Symbols:")?;
        for (ref symbol, ref id) in self.items.iter() {
            write!(f, "\n  {:?} => {:?}", id, symbol)?;
        }
        write!(f, "\n")
    }
}
impl Default for SymbolCollection {
    fn default() -> SymbolCollection { SymbolCollection{ items: HashMap::new() } }
}
impl SymbolCollection {

    pub fn new() -> SymbolCollection {
        SymbolCollection{ items: HashMap::new() }
    }

    pub fn intern(&mut self, value: String) -> SymbolID {
        if let Some(id) = self.items.get(&value) {
            return *id;
        }
        let newid = SymbolID(self.items.len() + 1);     // reserve 0
        self.items.insert(value, newid);
        return newid;
    }
    pub fn intern_str(&mut self, symbol: &str) -> SymbolID {
        if let Some(id) = self.items.get(symbol) {
            return *id;
        }
        let newid = SymbolID(self.items.len() + 1);     // reserve 0
        self.items.insert(symbol.to_owned(), newid);
        return newid;
    }

    pub fn get(&self, expect_id: SymbolID) -> Option<&str> {
        for (ref symbol, ref id) in self.items.iter() {
            if id == &&expect_id {
                return Some(symbol);
            }
        }
        return None;
    }
}

/// for test, make symbols with fixed id before analyze
#[macro_export]
macro_rules! make_symbols {
    ($($x:expr),*) => ({
        let mut retval = SymbolCollection::new();
        {
            let _retval = &mut retval; // `&mut` for statisfy 'unused mut', `_` for statisfy unused var
            $(
                _retval.intern_str($x);
            )*
        }
        retval
    });
    ($($x:expr,)*) => (make_messages![$($x),*])
}

#[cfg(test)] #[test]
fn intern_symbols() {

    let mut symbols = SymbolCollection::new();
    let id1 = symbols.intern("abc".to_owned());
    let id2 = symbols.intern("123".to_owned());
    let id3 = symbols.intern("abc".to_owned());
    assert!(id1 != id2);
    assert!(id2 != id3);
    assert!(id1 == id3);
    assert_eq!(symbols.get(id1), Some("abc"));
    assert_eq!(symbols.get(id2), Some("123"));
    assert_eq!(symbols.get(id3), Some("abc"));
    assert_eq!(symbols.get(SymbolID(123)), None);

    assert_eq!(id1.format(Some(&symbols)), "\"abc\"");
    assert_eq!(id2.format(Some(&symbols)), "\"123\"");
    assert_eq!(id3.format(Some(&symbols)), "\"abc\"");
    assert_eq!(SymbolID::from(42).format(Some(&symbols)), "\"<no-sym>\"");
    assert_eq!(id1.format(None), "#1");
    assert_eq!(id2.format(None), "#2");

    let mut symbols = make_symbols!["abc", "123", "abc"];
    assert_eq!(symbols.intern_str("abc"), symbols.intern_str("abc"));
}
<commit_msg>[codemap] fix an error in symbol def test macro<commit_after>///! fff-lang
///!
///! codemap/symbol_def
///! all kinds of strings, intern them to save memory and save copy time

use std::fmt;
use std::collections::HashMap;

#[derive(Eq, PartialEq, Clone, Copy, Hash)]
pub struct SymbolID(usize);
impl SymbolID { pub fn new(value: usize) -> SymbolID { SymbolID(value) } }
impl From<usize> for SymbolID { fn from(value: usize) -> SymbolID { SymbolID(value) } }
impl SymbolID {
    pub fn format(&self, symbols: Option<&SymbolCollection>) -> String {
        match symbols {
            None => format!("#{}", self.0),
            Some(symbols) => format!("{:?}", symbols.get(*self).unwrap_or("<no-sym>")),
        }
    }
}
impl fmt::Debug for SymbolID {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.format(None)) }
}

pub struct SymbolCollection {
    items: HashMap<String, SymbolID>,
}
impl fmt::Debug for SymbolCollection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Symbols:")?;
        for (ref symbol, ref id) in self.items.iter() {
            write!(f, "\n  {:?} => {:?}", id, symbol)?;
        }
        write!(f, "\n")
    }
}
impl Default for SymbolCollection {
    fn default() -> SymbolCollection { SymbolCollection{ items: HashMap::new() } }
}
impl SymbolCollection {

    pub fn new() -> SymbolCollection {
        SymbolCollection{ items: HashMap::new() }
    }

    pub fn intern(&mut self, value: String) -> SymbolID {
        if let Some(id) = self.items.get(&value) {
            return *id;
        }
        let newid = SymbolID(self.items.len() + 1);     // reserve 0
        self.items.insert(value, newid);
        return newid;
    }
    pub fn intern_str(&mut self, symbol: &str) -> SymbolID {
        if let Some(id) = self.items.get(symbol) {
            return *id;
        }
        let newid = SymbolID(self.items.len() + 1);     // reserve 0
        self.items.insert(symbol.to_owned(), newid);
        return newid;
    }

    pub fn get(&self, expect_id: SymbolID) -> Option<&str> {
        for (ref symbol, ref id) in self.items.iter() {
            if id == &&expect_id {
                return Some(symbol);
            }
        }
        return None;
    }
}

/// for test, make symbols with fixed id before analyze
#[macro_export]
macro_rules! make_symbols {
    ($($x:expr),*) => ({
        let mut retval = SymbolCollection::new();
        {
            let _retval = &mut retval; // `&mut` for statisfy 'unused mut', `_` for statisfy unused var
            $(
                _retval.intern_str($x);
            )*
        }
        retval
    });
    ($($x:expr,)*) => (make_symbols![$($x),*])
}

#[cfg(test)] #[test]
fn intern_symbols() {

    let mut symbols = SymbolCollection::new();
    let id1 = symbols.intern("abc".to_owned());
    let id2 = symbols.intern("123".to_owned());
    let id3 = symbols.intern("abc".to_owned());
    assert!(id1 != id2);
    assert!(id2 != id3);
    assert!(id1 == id3);
    assert_eq!(symbols.get(id1), Some("abc"));
    assert_eq!(symbols.get(id2), Some("123"));
    assert_eq!(symbols.get(id3), Some("abc"));
    assert_eq!(symbols.get(SymbolID(123)), None);

    assert_eq!(id1.format(Some(&symbols)), "\"abc\"");
    assert_eq!(id2.format(Some(&symbols)), "\"123\"");
    assert_eq!(id3.format(Some(&symbols)), "\"abc\"");
    assert_eq!(SymbolID::from(42).format(Some(&symbols)), "\"<no-sym>\"");
    assert_eq!(id1.format(None), "#1");
    assert_eq!(id2.format(None), "#2");

    let mut symbols = make_symbols!["abc", "123", "abc"];
    assert_eq!(symbols.intern_str("abc"), symbols.intern_str("abc"));
}
<|endoftext|>