<commit_before>use std::sync::Arc;

use ra_syntax::{
    AstNode, SourceFile, TreeArc, AstPtr,
    ast::{self, ModuleItemOwner, NameOwner},
};
use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
use rustc_hash::FxHashMap;

use crate::{
    SourceItemId, Path, ModuleSource, Name,
    HirFileId, MacroCallLoc, AsName, PerNs, Function,
    ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type,
    ids::LocationCtx, PersistentHirDatabase,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ImportId(RawId);
impl_arena_id!(ImportId);

#[derive(Debug, PartialEq, Eq)]
pub(super) struct ImportData {
    pub(super) path: Path,
    pub(super) alias: Option<Name>,
    pub(super) is_glob: bool,
}

/// A set of items and imports declared inside a module, without relation to
/// other modules.
///
/// This sits in-between raw syntax and name resolution and allows us to avoid
/// recomputing name res: if two instance of `InputModuleItems` are the same, we
/// can avoid redoing name resolution.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct LoweredModule {
    pub(crate) declarations: FxHashMap<Name, PerNs<ModuleDef>>,
    pub(super) imports: Arena<ImportId, ImportData>,
}

#[derive(Debug, Default, PartialEq, Eq)]
pub struct ImportSourceMap {
    map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>,
}

impl ImportSourceMap {
    fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) {
        self.map.insert(import, AstPtr::new(segment))
    }

    pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> {
        let file = match source {
            ModuleSource::SourceFile(file) => &*file,
            ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
        };

        self.map[import].to_node(file).to_owned()
    }
}

impl LoweredModule {
    pub(crate) fn lower_module_module_query(
        db: &impl PersistentHirDatabase,
        module: Module,
    ) -> Arc<LoweredModule> {
        db.lower_module(module).0
    }

    pub(crate) fn lower_module_source_map_query(
        db: &impl PersistentHirDatabase,
        module: Module,
    ) -> Arc<ImportSourceMap> {
        db.lower_module(module).1
    }

    pub(crate) fn lower_module_query(
        db: &impl PersistentHirDatabase,
        module: Module,
    ) -> (Arc<LoweredModule>, Arc<ImportSourceMap>) {
        let (file_id, source) = module.definition_source(db);
        let file_id: HirFileId = file_id.into();
        let mut source_map = ImportSourceMap::default();
        let mut res = LoweredModule::default();
        match source {
            ModuleSource::SourceFile(it) => res.fill(
                &mut source_map,
                db,
                module,
                file_id,
                &mut it.items_with_macros(),
            ),
            ModuleSource::Module(it) => {
                if let Some(item_list) = it.item_list() {
                    res.fill(
                        &mut source_map,
                        db,
                        module,
                        file_id,
                        &mut item_list.items_with_macros(),
                    )
                }
            }
        };
        (Arc::new(res), Arc::new(source_map))
    }

    fn fill(
        &mut self,
        source_map: &mut ImportSourceMap,
        db: &impl PersistentHirDatabase,
        module: Module,
        file_id: HirFileId,
        items: &mut Iterator<Item = ast::ItemOrMacro>,
    ) {
        let file_items = db.file_items(file_id);

        for item in items {
            match item {
                ast::ItemOrMacro::Item(it) => {
                    self.add_def_id(source_map, db, module, file_id, it);
                }
                ast::ItemOrMacro::Macro(macro_call) => {
                    let item_id = file_items.id_of_unchecked(macro_call.syntax());
                    let loc = MacroCallLoc {
                        module,
                        source_item_id: SourceItemId { file_id, item_id },
                    };
                    let id = loc.id(db);
                    let file_id = HirFileId::from(id);
                    //FIXME: expand recursively
                    for item in db.hir_parse(file_id).items() {
                        self.add_def_id(source_map, db, module, file_id, item);
                    }
                }
            }
        }
    }

    fn add_def_id(
        &mut self,
        source_map: &mut ImportSourceMap,
        db: &impl PersistentHirDatabase,
        module: Module,
        file_id: HirFileId,
        item: &ast::ModuleItem,
    ) {
        let ctx = LocationCtx::new(db, module, file_id);
        match item.kind() {
            ast::ModuleItemKind::StructDef(it) => {
                if let Some(name) = it.name() {
                    let s = Struct { id: ctx.to_def(it) };
                    let s: ModuleDef = s.into();
                    self.declarations.insert(name.as_name(), PerNs::both(s, s));
                }
            }
            ast::ModuleItemKind::EnumDef(it) => {
                if let Some(name) = it.name() {
                    let e = Enum { id: ctx.to_def(it) };
                    let e: ModuleDef = e.into();
                    self.declarations.insert(name.as_name(), PerNs::types(e));
                }
            }
            ast::ModuleItemKind::FnDef(it) => {
                if let Some(name) = it.name() {
                    let func = Function { id: ctx.to_def(it) };
                    self.declarations
                        .insert(name.as_name(), PerNs::values(func.into()));
                }
            }
            ast::ModuleItemKind::TraitDef(it) => {
                if let Some(name) = it.name() {
                    let t = Trait { id: ctx.to_def(it) };
                    self.declarations
                        .insert(name.as_name(), PerNs::types(t.into()));
                }
            }
            ast::ModuleItemKind::TypeDef(it) => {
                if let Some(name) = it.name() {
                    let t = Type { id: ctx.to_def(it) };
                    self.declarations
                        .insert(name.as_name(), PerNs::types(t.into()));
                }
            }
            ast::ModuleItemKind::ImplBlock(_) => {
                // impls don't define items
            }
            ast::ModuleItemKind::UseItem(it) => {
                self.add_use_item(source_map, it);
            }
            ast::ModuleItemKind::ExternCrateItem(_) => {
                // TODO
            }
            ast::ModuleItemKind::ConstDef(it) => {
                if let Some(name) = it.name() {
                    let c = Const { id: ctx.to_def(it) };
                    self.declarations
                        .insert(name.as_name(), PerNs::values(c.into()));
                }
            }
            ast::ModuleItemKind::StaticDef(it) => {
                if let Some(name) = it.name() {
                    let s = Static { id: ctx.to_def(it) };
                    self.declarations
                        .insert(name.as_name(), PerNs::values(s.into()));
                }
            }
            ast::ModuleItemKind::Module(_) => {
                // modules are handled separately direclty by nameres
            }
        };
    }

    fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) {
        Path::expand_use_item(item, |path, segment, alias| {
            let import = self.imports.alloc(ImportData {
                path,
                alias,
                is_glob: segment.is_none(),
            });
            if let Some(segment) = segment {
                source_map.insert(import, segment)
            }
        })
    }
}
<commit_msg>Lower extern crates to imports<commit_after>use std::sync::Arc;

use ra_syntax::{
    AstNode, SourceFile, TreeArc, AstPtr,
    ast::{self, ModuleItemOwner, NameOwner},
};
use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
use rustc_hash::FxHashMap;

use crate::{
    SourceItemId, Path, PathKind, ModuleSource, Name,
    HirFileId, MacroCallLoc, AsName, PerNs, Function,
    ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type,
    ids::LocationCtx, PersistentHirDatabase,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ImportId(RawId);
impl_arena_id!(ImportId);

#[derive(Debug, PartialEq, Eq)]
pub(super) struct ImportData {
    pub(super) path: Path,
    pub(super) alias: Option<Name>,
    pub(super) is_glob: bool,
}

/// A set of items and imports declared inside a module, without relation to
/// other modules.
///
/// This sits in-between raw syntax and name resolution and allows us to avoid
/// recomputing name res: if two instance of `InputModuleItems` are the same, we
/// can avoid redoing name resolution.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct LoweredModule {
    pub(crate) declarations: FxHashMap<Name, PerNs<ModuleDef>>,
    pub(super) imports: Arena<ImportId, ImportData>,
}

#[derive(Debug, Default, PartialEq, Eq)]
pub struct ImportSourceMap {
    map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>,
}

impl ImportSourceMap {
    fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) {
        self.map.insert(import, AstPtr::new(segment))
    }

    pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> {
        let file = match source {
            ModuleSource::SourceFile(file) => &*file,
            ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
        };

        self.map[import].to_node(file).to_owned()
    }
}

impl LoweredModule {
    pub(crate) fn lower_module_module_query(
        db: &impl PersistentHirDatabase,
        module: Module,
    ) -> Arc<LoweredModule> {
        db.lower_module(module).0
    }

    pub(crate) fn lower_module_source_map_query(
        db: &impl PersistentHirDatabase,
        module: Module,
    ) -> Arc<ImportSourceMap> {
        db.lower_module(module).1
    }

    pub(crate) fn lower_module_query(
        db: &impl PersistentHirDatabase,
        module: Module,
    ) -> (Arc<LoweredModule>, Arc<ImportSourceMap>) {
        let (file_id, source) = module.definition_source(db);
        let file_id: HirFileId = file_id.into();
        let mut source_map = ImportSourceMap::default();
        let mut res = LoweredModule::default();
        match source {
            ModuleSource::SourceFile(it) => res.fill(
                &mut source_map,
                db,
                module,
                file_id,
                &mut it.items_with_macros(),
            ),
            ModuleSource::Module(it) => {
                if let Some(item_list) = it.item_list() {
                    res.fill(
                        &mut source_map,
                        db,
                        module,
                        file_id,
                        &mut item_list.items_with_macros(),
                    )
                }
            }
        };
        (Arc::new(res), Arc::new(source_map))
    }

    fn fill(
        &mut self,
        source_map: &mut ImportSourceMap,
        db: &impl PersistentHirDatabase,
        module: Module,
        file_id: HirFileId,
        items: &mut Iterator<Item = ast::ItemOrMacro>,
    ) {
        let file_items = db.file_items(file_id);

        for item in items {
            match item {
                ast::ItemOrMacro::Item(it) => {
                    self.add_def_id(source_map, db, module, file_id, it);
                }
                ast::ItemOrMacro::Macro(macro_call) => {
                    let item_id = file_items.id_of_unchecked(macro_call.syntax());
                    let loc = MacroCallLoc {
                        module,
                        source_item_id: SourceItemId { file_id, item_id },
                    };
                    let id = loc.id(db);
                    let file_id = HirFileId::from(id);
                    //FIXME: expand recursively
                    for item in db.hir_parse(file_id).items() {
                        self.add_def_id(source_map, db, module, file_id, item);
                    }
                }
            }
        }
    }

    fn add_def_id(
        &mut self,
        source_map: &mut ImportSourceMap,
        db: &impl PersistentHirDatabase,
        module: Module,
        file_id: HirFileId,
        item: &ast::ModuleItem,
    ) {
        let ctx = LocationCtx::new(db, module, file_id);
        match item.kind() {
            ast::ModuleItemKind::StructDef(it) => {
                if let Some(name) = it.name() {
                    let s = Struct { id: ctx.to_def(it) };
                    let s: ModuleDef = s.into();
                    self.declarations.insert(name.as_name(), PerNs::both(s, s));
                }
            }
            ast::ModuleItemKind::EnumDef(it) => {
                if let Some(name) = it.name() {
                    let e = Enum { id: ctx.to_def(it) };
                    let e: ModuleDef = e.into();
                    self.declarations.insert(name.as_name(), PerNs::types(e));
                }
            }
            ast::ModuleItemKind::FnDef(it) => {
                if let Some(name) = it.name() {
                    let func = Function { id: ctx.to_def(it) };
                    self.declarations
                        .insert(name.as_name(), PerNs::values(func.into()));
                }
            }
            ast::ModuleItemKind::TraitDef(it) => {
                if let Some(name) = it.name() {
                    let t = Trait { id: ctx.to_def(it) };
                    self.declarations
                        .insert(name.as_name(), PerNs::types(t.into()));
                }
            }
            ast::ModuleItemKind::TypeDef(it) => {
                if let Some(name) = it.name() {
                    let t = Type { id: ctx.to_def(it) };
                    self.declarations
                        .insert(name.as_name(), PerNs::types(t.into()));
                }
            }
            ast::ModuleItemKind::ImplBlock(_) => {
                // impls don't define items
            }
            ast::ModuleItemKind::UseItem(it) => {
                self.add_use_item(source_map, it);
            }
            ast::ModuleItemKind::ExternCrateItem(it) => {
                // Lower `extern crate x` to `use ::x`. This is kind of cheating
                // and only works if we always interpret absolute paths in the
                // 2018 style; otherwise `::x` could also refer to a module in
                // the crate root.
                if let Some(name_ref) = it.name_ref() {
                    let mut path = Path::from_name_ref(name_ref);
                    path.kind = PathKind::Abs;
                    let alias = it.alias().and_then(|a| a.name()).map(AsName::as_name);
                    self.imports.alloc(ImportData {
                        path,
                        alias,
                        is_glob: false,
                    });
                }
            }
            ast::ModuleItemKind::ConstDef(it) => {
                if let Some(name) = it.name() {
                    let c = Const { id: ctx.to_def(it) };
                    self.declarations
                        .insert(name.as_name(), PerNs::values(c.into()));
                }
            }
            ast::ModuleItemKind::StaticDef(it) => {
                if let Some(name) = it.name() {
                    let s = Static { id: ctx.to_def(it) };
                    self.declarations
                        .insert(name.as_name(), PerNs::values(s.into()));
                }
            }
            ast::ModuleItemKind::Module(_) => {
                // modules are handled separately direclty by nameres
            }
        };
    }

    fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) {
        Path::expand_use_item(item, |path, segment, alias| {
            let import = self.imports.alloc(ImportData {
                path,
                alias,
                is_glob: segment.is_none(),
            });
            if let Some(segment) = segment {
                source_map.insert(import, segment)
            }
        })
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

mod address;

use super::{
    DirectDownload, EntryPoint, Metadata, PrepareLocalInstall, Result, RuntimeSettings, Settings,
    State, StateChangeImpl, Validation,
};
use slog_scope::{error, info, trace};
use std::path::PathBuf;

pub(crate) use address::{
    AbortDownloadResponse, Addr, Message, ProbeResponse, Response, StateResponse,
};

pub(super) struct StateMachine {
    state: State,
    context: Context,
}

pub struct Context {
    pub(super) communication: Channel<(Message, async_channel::Sender<Result<Response>>)>,
    pub(super) waker: Channel<()>,
    pub settings: Settings,
    pub runtime_settings: RuntimeSettings,
    pub firmware: Metadata,
}

pub(super) struct Channel<T> {
    pub(super) sender: async_channel::Sender<T>,
    pub(super) receiver: async_channel::Receiver<T>,
}

impl<T> Channel<T> {
    fn new(cap: usize) -> Self {
        let (sender, receiver) = async_channel::bounded(cap);
        Channel { sender, receiver }
    }
}

impl CommunicationState for State {}

#[async_trait::async_trait]
pub(super) trait CommunicationState: StateChangeImpl {
    async fn handle_communication(
        &self,
        msg: address::Message,
        responder: async_channel::Sender<Result<address::Response>>,
        context: &mut Context,
    ) -> Option<State> {
        trace!("received external request: {:?}", msg);

        let res = match msg {
            address::Message::Info => {
                let state = self.name().to_owned();
                Ok((
                    address::Response::Info(Box::new(sdk::api::info::Response {
                        state,
                        version: crate::version().to_string(),
                        config: context.settings.0.clone(),
                        firmware: context.firmware.0.clone(),
                        runtime_settings: context.runtime_settings.inner.clone(),
                    })),
                    None,
                ))
            }
            address::Message::Probe(custom_server) => self
                .handle_probe(context, custom_server)
                .await
                .map(|(res, st)| (address::Response::Probe(res), st)),
            address::Message::AbortDownload => self
                .handle_abort_download(context)
                .await
                .map(|(res, st)| (address::Response::AbortDownload(res), st)),
            address::Message::LocalInstall(update_file) => self
                .handle_local_install(context, update_file)
                .await
                .map(|(res, st)| (address::Response::LocalInstall(res), st)),
            address::Message::RemoteInstall(url) => self
                .handle_remote_install(context, url)
                .await
                .map(|(res, st)| (address::Response::RemoteInstall(res), st)),
        };

        match res {
            Ok((response, state)) => {
                responder.send(Ok(response)).await.ok()?;
                state
            }
            Err(e) => {
                error!("Request failed with: {}", e);
                responder.send(Err(e)).await.ok()?;
                None
            }
        }
    }

    async fn handle_probe(
        &self,
        context: &mut Context,
        custom_server: Option<String>,
    ) -> Result<(address::ProbeResponse, Option<State>)> {
        use chrono::Utc;
        use cloud::api::ProbeResponse;

        if !self.is_preemptive_state() {
            let name = self.name().to_owned();
            return Ok((address::ProbeResponse::Busy(name), None));
        }
        // Starting logging a new scope of operation since we are
        // starting to handle a user request
        crate::logger::start_memory_logging();
        info!("Probing the server as requested by the user");

        if let Some(server_address) = custom_server {
            context.runtime_settings.set_custom_server_address(&server_address);
        }

        match crate::CloudClient::new(context.server_address())
            .probe(context.runtime_settings.retries(), context.firmware.as_cloud_metadata())
            .await?
        {
            ProbeResponse::ExtraPoll(s) => {
                info!("server responded with extra poll of {} seconds", s);
                Ok((address::ProbeResponse::Delayed(s), None))
            }

            ProbeResponse::NoUpdate => {
                info!("no update is current available for this device");
                context.waker.sender.send(()).await?;

                // Store timestamp of last polling
                context.runtime_settings.set_last_polling(Utc::now())?;
                Ok((address::ProbeResponse::Unavailable, Some(State::EntryPoint(EntryPoint {}))))
            }

            ProbeResponse::Update(package, sign) => {
                info!("update received: {} ({})", package.version(), package.package_uid());
                context.waker.sender.send(()).await?;

                // Store timestamp of last polling
                context.runtime_settings.set_last_polling(Utc::now())?;
                Ok((
                    address::ProbeResponse::Available,
                    Some(State::Validation(Validation { package, sign, require_download: true })),
                ))
            }
        }
    }

    async fn handle_abort_download(
        &self,
        _: &Context,
    ) -> Result<(address::AbortDownloadResponse, Option<State>)> {
        if self.is_handling_download() {
            Ok((
                address::AbortDownloadResponse::RequestAccepted,
                Some(State::EntryPoint(EntryPoint {})),
            ))
        } else {
            Ok((address::AbortDownloadResponse::InvalidState, None))
        }
    }

    async fn handle_local_install(
        &self,
        context: &Context,
        update_file: PathBuf,
    ) -> Result<(address::StateResponse, Option<State>)> {
        let name = self.name().to_owned();
        if self.is_preemptive_state() {
            // Starting logging a new scope of operation since we are
            // starting to handle a user request
            crate::logger::start_memory_logging();
            context.waker.sender.send(()).await?;

            Ok((
                address::StateResponse::RequestAccepted(name),
                Some(State::PrepareLocalInstall(PrepareLocalInstall { update_file })),
            ))
        } else {
            Ok((address::StateResponse::InvalidState(name), None))
        }
    }

    async fn handle_remote_install(
        &self,
        context: &Context,
        url: String,
    ) -> Result<(address::StateResponse, Option<State>)> {
        let name = self.name().to_owned();

        if self.is_preemptive_state() {
            // Starting logging a new scope of operation since we are
            // starting to handle a user request
            crate::logger::start_memory_logging();
            context.waker.sender.send(()).await?;

            Ok((
                address::StateResponse::RequestAccepted(name),
                Some(State::DirectDownload(DirectDownload { url })),
            ))
        } else {
            Ok((address::StateResponse::InvalidState(name), None))
        }
    }
}

impl Context {
    pub(crate) fn new(
        settings: Settings,
        runtime_settings: RuntimeSettings,
        firmware: Metadata,
    ) -> Self {
        Context {
            communication: Channel::new(10),
            waker: Channel::new(1),
            settings,
            runtime_settings,
            firmware,
        }
    }

    pub(super) fn server_address(&self) -> &str {
        self.runtime_settings
            .custom_server_address()
            .unwrap_or(&self.settings.network.server_address)
    }
}

#[derive(Debug)]
pub(super) enum StepTransition {
    Delayed(chrono::Duration),
    Immediate,
    Never,
}

impl StateMachine {
    pub(super) fn new(
        state: State,
        settings: Settings,
        runtime_settings: RuntimeSettings,
        firmware: Metadata,
    ) -> Self {
        StateMachine { state, context: Context::new(settings, runtime_settings, firmware) }
    }

    pub(super) fn address(&self) -> Addr {
        Addr { message: self.context.communication.sender.clone() }
    }

    pub(super) async fn start(mut self) {
        loop {
            // Since the loop is already currently running, we can
            // discharges any wake message received.
            let _ = self.context.waker.receiver.try_recv();

            self.consume_pending_communication().await;

            let (state, transition) = self
                .state
                .handle(&mut self.context)
                .await
                .unwrap_or_else(|e| (State::from(e), StepTransition::Immediate));
            self.state = state;

            match transition {
                StepTransition::Immediate => {}
                StepTransition::Delayed(t) => {
                    trace!("delaying transition for: {} seconds", t.num_seconds());
                    let waker = self.context.waker.receiver.clone();

                    let sleep_fut = tokio::time::sleep(t.to_std().unwrap());
                    let waker_fut = async {
                        let _ = waker.recv().await;
                    };
                    let comm_fut = self.await_communication();

                    futures_util::pin_mut!(sleep_fut);
                    futures_util::pin_mut!(waker_fut);
                    futures_util::pin_mut!(comm_fut);

                    let _ = futures_util::future::select(
                        futures_util::future::select(sleep_fut, waker_fut),
                        comm_fut,
                    )
                    .await;
                }
                StepTransition::Never => {
                    trace!("stopping transition until awoken");
                    let waker_recv = self.context.waker.receiver.clone();
                    let recv_fut = waker_recv.recv();
                    let comm_fut = async {
                        self.await_communication().await;
                        std::result::Result::<_, async_channel::RecvError>::Ok(())
                    };

                    // recv_fut doesn't need to be pinned as it doesn't capture any context
                    futures_util::pin_mut!(comm_fut);
                    let _ = futures_util::future::select(recv_fut, comm_fut).await;
                }
            }
        }
    }

    async fn consume_pending_communication(&mut self) {
        while let Ok((msg, responder)) = self.context.communication.receiver.try_recv() {
            if let Some(new_state) =
                self.state.handle_communication(msg, responder, &mut self.context).await
            {
                self.state = new_state;
            }
        }
    }

    async fn await_communication(&mut self) {
        while let Ok((msg, responder)) = self.context.communication.receiver.recv().await {
            if let Some(new_state) =
                self.state.handle_communication(msg, responder, &mut self.context).await
            {
                self.state = new_state;
            }
        }
    }
}
<commit_msg>updatehub: states: machine: use 0 seconds as delaying default time<commit_after>// Copyright (C) 2020 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

mod address;

use super::{
    DirectDownload, EntryPoint, Metadata, PrepareLocalInstall, Result, RuntimeSettings, Settings,
    State, StateChangeImpl, Validation,
};
use slog_scope::{error, info, trace};
use std::path::PathBuf;

pub(crate) use address::{
    AbortDownloadResponse, Addr, Message, ProbeResponse, Response, StateResponse,
};

pub(super) struct StateMachine {
    state: State,
    context: Context,
}

pub struct Context {
    pub(super) communication: Channel<(Message, async_channel::Sender<Result<Response>>)>,
    pub(super) waker: Channel<()>,
    pub settings: Settings,
    pub runtime_settings: RuntimeSettings,
    pub firmware: Metadata,
}

pub(super) struct Channel<T> {
    pub(super) sender: async_channel::Sender<T>,
    pub(super) receiver: async_channel::Receiver<T>,
}

impl<T> Channel<T> {
    fn new(cap: usize) -> Self {
        let (sender, receiver) = async_channel::bounded(cap);
        Channel { sender, receiver }
    }
}

impl CommunicationState for State {}

#[async_trait::async_trait]
pub(super) trait CommunicationState: StateChangeImpl {
    async fn handle_communication(
        &self,
        msg: address::Message,
        responder: async_channel::Sender<Result<address::Response>>,
        context: &mut Context,
    ) -> Option<State> {
        trace!("received external request: {:?}", msg);

        let res = match msg {
            address::Message::Info => {
                let state = self.name().to_owned();
                Ok((
                    address::Response::Info(Box::new(sdk::api::info::Response {
                        state,
                        version: crate::version().to_string(),
                        config: context.settings.0.clone(),
                        firmware: context.firmware.0.clone(),
                        runtime_settings: context.runtime_settings.inner.clone(),
                    })),
                    None,
                ))
            }
            address::Message::Probe(custom_server) => self
                .handle_probe(context, custom_server)
                .await
                .map(|(res, st)| (address::Response::Probe(res), st)),
            address::Message::AbortDownload => self
                .handle_abort_download(context)
                .await
                .map(|(res, st)| (address::Response::AbortDownload(res), st)),
            address::Message::LocalInstall(update_file) => self
                .handle_local_install(context, update_file)
                .await
                .map(|(res, st)| (address::Response::LocalInstall(res), st)),
            address::Message::RemoteInstall(url) => self
                .handle_remote_install(context, url)
                .await
                .map(|(res, st)| (address::Response::RemoteInstall(res), st)),
        };

        match res {
            Ok((response, state)) => {
                responder.send(Ok(response)).await.ok()?;
                state
            }
            Err(e) => {
                error!("Request failed with: {}", e);
                responder.send(Err(e)).await.ok()?;
                None
            }
        }
    }

    async fn handle_probe(
        &self,
        context: &mut Context,
        custom_server: Option<String>,
    ) -> Result<(address::ProbeResponse, Option<State>)> {
        use chrono::Utc;
        use cloud::api::ProbeResponse;

        if !self.is_preemptive_state() {
            let name = self.name().to_owned();
            return Ok((address::ProbeResponse::Busy(name), None));
        }
        // Starting logging a new scope of operation since we are
        // starting to handle a user request
        crate::logger::start_memory_logging();
        info!("Probing the server as requested by the user");

        if let Some(server_address) = custom_server {
            context.runtime_settings.set_custom_server_address(&server_address);
        }

        match crate::CloudClient::new(context.server_address())
            .probe(context.runtime_settings.retries(), context.firmware.as_cloud_metadata())
            .await?
        {
            ProbeResponse::ExtraPoll(s) => {
                info!("server responded with extra poll of {} seconds", s);
                Ok((address::ProbeResponse::Delayed(s), None))
            }

            ProbeResponse::NoUpdate => {
                info!("no update is current available for this device");
                context.waker.sender.send(()).await?;

                // Store timestamp of last polling
                context.runtime_settings.set_last_polling(Utc::now())?;
                Ok((address::ProbeResponse::Unavailable, Some(State::EntryPoint(EntryPoint {}))))
            }

            ProbeResponse::Update(package, sign) => {
                info!("update received: {} ({})", package.version(), package.package_uid());
                context.waker.sender.send(()).await?;

                // Store timestamp of last polling
                context.runtime_settings.set_last_polling(Utc::now())?;
                Ok((
                    address::ProbeResponse::Available,
                    Some(State::Validation(Validation { package, sign, require_download: true })),
                ))
            }
        }
    }

    async fn handle_abort_download(
        &self,
        _: &Context,
    ) -> Result<(address::AbortDownloadResponse, Option<State>)> {
        if self.is_handling_download() {
            Ok((
                address::AbortDownloadResponse::RequestAccepted,
                Some(State::EntryPoint(EntryPoint {})),
            ))
        } else {
            Ok((address::AbortDownloadResponse::InvalidState, None))
        }
    }

    async fn handle_local_install(
        &self,
        context: &Context,
        update_file: PathBuf,
    ) -> Result<(address::StateResponse, Option<State>)> {
        let name = self.name().to_owned();
        if self.is_preemptive_state() {
            // Starting logging a new scope of operation since we are
            // starting to handle a user request
            crate::logger::start_memory_logging();
            context.waker.sender.send(()).await?;

            Ok((
                address::StateResponse::RequestAccepted(name),
                Some(State::PrepareLocalInstall(PrepareLocalInstall { update_file })),
            ))
        } else {
            Ok((address::StateResponse::InvalidState(name), None))
        }
    }

    async fn handle_remote_install(
        &self,
        context: &Context,
        url: String,
    ) -> Result<(address::StateResponse, Option<State>)> {
        let name = self.name().to_owned();

        if self.is_preemptive_state() {
            // Starting logging a new scope of operation since we are
            // starting to handle a user request
            crate::logger::start_memory_logging();
            context.waker.sender.send(()).await?;

            Ok((
                address::StateResponse::RequestAccepted(name),
                Some(State::DirectDownload(DirectDownload { url })),
            ))
        } else {
            Ok((address::StateResponse::InvalidState(name), None))
        }
    }
}

impl Context {
    pub(crate) fn new(
        settings: Settings,
        runtime_settings: RuntimeSettings,
        firmware: Metadata,
    ) -> Self {
        Context {
            communication: Channel::new(10),
            waker: Channel::new(1),
            settings,
            runtime_settings,
            firmware,
        }
    }

    pub(super) fn server_address(&self) -> &str {
        self.runtime_settings
            .custom_server_address()
            .unwrap_or(&self.settings.network.server_address)
    }
}

#[derive(Debug)]
pub(super) enum StepTransition {
    Delayed(chrono::Duration),
    Immediate,
    Never,
}

impl StateMachine {
    pub(super) fn new(
        state: State,
        settings: Settings,
        runtime_settings: RuntimeSettings,
        firmware: Metadata,
    ) -> Self {
        StateMachine { state, context: Context::new(settings, runtime_settings, firmware) }
    }

    pub(super) fn address(&self) -> Addr {
        Addr { message: self.context.communication.sender.clone() }
    }

    pub(super) async fn start(mut self) {
        loop {
            // Since the loop is already currently running, we can
            // discharges any wake message received.
            let _ = self.context.waker.receiver.try_recv();

            self.consume_pending_communication().await;

            let (state, transition) = self
                .state
                .handle(&mut self.context)
                .await
                .unwrap_or_else(|e| (State::from(e), StepTransition::Immediate));
            self.state = state;

            match transition {
                StepTransition::Immediate => {}
                StepTransition::Delayed(t) => {
                    trace!("delaying transition for: {} seconds", t.num_seconds());
                    let waker = self.context.waker.receiver.clone();

                    let sleep_fut = tokio::time::sleep(t.to_std().unwrap_or_default());
                    let waker_fut = async {
                        let _ = waker.recv().await;
                    };
                    let comm_fut = self.await_communication();

                    futures_util::pin_mut!(sleep_fut);
                    futures_util::pin_mut!(waker_fut);
                    futures_util::pin_mut!(comm_fut);

                    let _ = futures_util::future::select(
                        futures_util::future::select(sleep_fut, waker_fut),
                        comm_fut,
                    )
                    .await;
                }
                StepTransition::Never => {
                    trace!("stopping transition until awoken");
                    let waker_recv = self.context.waker.receiver.clone();
                    let recv_fut = waker_recv.recv();
                    let comm_fut = async {
                        self.await_communication().await;
                        std::result::Result::<_, async_channel::RecvError>::Ok(())
                    };

                    // recv_fut doesn't need to be pinned as it doesn't capture any context
                    futures_util::pin_mut!(comm_fut);
                    let _ = futures_util::future::select(recv_fut, comm_fut).await;
                }
            }
        }
    }

    async fn consume_pending_communication(&mut self) {
        while let Ok((msg, responder)) = self.context.communication.receiver.try_recv() {
            if let Some(new_state) =
                self.state.handle_communication(msg, responder, &mut self.context).await
            {
                self.state = new_state;
            }
        }
    }

    async fn await_communication(&mut self) {
        while let Ok((msg, responder)) = self.context.communication.receiver.recv().await {
            if let Some(new_state) =
                self.state.handle_communication(msg, responder, &mut self.context).await
            {
                self.state = new_state;
            }
        }
    }
}
<|endoftext|>


<commit_before>// error-pattern: calling a function with ABI C-unwind using caller ABI C
#![feature(c_unwind)]

//! Unwinding when the caller ABI is "C" (without "-unwind") is UB.
//! Currently we detect the ABI mismatch; we could probably allow such calls in principle one day
//! but then we have to detect the unexpected unwinding.
//! FIXME: `-Zmiri-disable-abi-check` does not work for this test because function pointers are
//! always allowed to unwind.

extern "C-unwind" fn unwind() {
    panic!();
}

fn main() {
    let unwind: extern "C-unwind" fn() = unwind;
    let unwind: extern "C" fn() = unsafe { std::mem::transmute(unwind) };
    std::panic::catch_unwind(|| unwind()).unwrap_err();
}
<commit_msg>Remove FIXME in `tests/compile-fail/panic/bad_unwind.rs`<commit_after>// error-pattern: calling a function with ABI C-unwind using caller ABI C
#![feature(c_unwind)]

//! Unwinding when the caller ABI is "C" (without "-unwind") is UB.
//! Currently we detect the ABI mismatch; we could probably allow such calls in principle one day
//! but then we have to detect the unexpected unwinding.

extern "C-unwind" fn unwind() {
    panic!();
}

fn main() {
    let unwind: extern "C-unwind" fn() = unwind;
    let unwind: extern "C" fn() = unsafe { std::mem::transmute(unwind) };
    std::panic::catch_unwind(|| unwind()).unwrap_err();
}
<|endoftext|>


<commit_before>use crate::index::index_ro;
use crates_index_diff::{Change, CrateVersion, Index};
use git_repository as git;

#[test]
fn addition() -> crate::Result {
    let changes = changes(index_ro()?, ":/initial commit")?;
    assert_eq!(changes.len(), 3228);
    assert!(matches!(
        changes
            .first()
            .and_then(|c| c.added().map(|v| v.name.as_str())),
        Some("gi-get-artifact")
    ));
    assert!(matches!(
        changes.last().expect("present"),
        Change::Added(CrateVersion {name, ..}) if name == "gizmo"
    ));
    Ok(())
}

#[test]
fn deletion() -> crate::Result {
    let changes = changes(index_ro()?, "@~327")?;
    assert_eq!(changes.len(), 1);
    assert_eq!(changes.first().and_then(|c| c.deleted()), Some("girl"));
    Ok(())
}

#[test]
fn new_version() -> crate::Result {
    let changes = changes(index_ro()?, ":/Updating crate `git-repository#0.22.1`")?;
    assert_eq!(changes.len(), 1);
    assert_eq!(
        changes
            .first()
            .and_then(|c| c.added().map(|v| v.name.as_str())),
        Some("git-repository")
    );
    Ok(())
}

#[test]
fn yanked() -> crate::Result {
    let changes = changes(index_ro()?, ":/Yanking crate `github_release_rs#0.1.0`")?;
    assert_eq!(changes.len(), 1);
    assert_eq!(
        changes
            .first()
            .and_then(|c| c.yanked().map(|v| v.name.as_str())),
        Some("github_release_rs")
    );
    Ok(())
}

#[test]
fn yanked_in_new_file() -> crate::Result {
    let changes = changes(index_ro()?, ":/reproduce issue #19")?;
    assert_eq!(changes.len(), 1);
    assert_eq!(
        changes
            .first()
            .and_then(|c| c.yanked().map(|v| v.name.as_str())),
        Some("allowed")
    );
    Ok(())
}

#[test]
fn unyanked_crates_recognized_as_added() -> crate::Result {
    let changes = changes(index_ro()?, ":/Unyanking crate `git2mail#0.3.2`")?;
    assert_eq!(changes.len(), 1);
    assert_eq!(
        changes
            .first()
            .and_then(|c| c.added().map(|v| v.name.as_str())),
        Some("git2mail")
    );
    Ok(())
}

#[test]
fn normalization() -> crate::Result {
    let changes = changes(index_ro()?, ":/normalize")?;
    assert_eq!(
        changes.len(),
        0,
        "normalization changes the representation, but the data itself stays the same"
    );
    Ok(())
}

fn changes(mut index: Index, revspec: &str) -> crate::Result<Vec<Change>> {
    let (prev, current) = {
        let repo = index.repository_mut();
        repo.object_cache_size_if_unset(4 * 1024 * 1024);
        let commit = repo.rev_parse(revspec)?.single().unwrap();
        let ancestor_tree = commit
            .object()?
            .into_commit()
            .parent_ids()
            .next()
            .and_then(|parent| {
                parent
                    .object()
                    .ok()?
                    .into_commit()
                    .tree_id()
                    .ok()
                    .map(|id| id.detach())
            })
            .unwrap_or_else(|| git::hash::ObjectId::empty_tree(repo.object_hash()));
        (ancestor_tree, commit.detach())
    };
    Ok(index.changes_between_commits(prev, current)?)
}
<commit_msg>Make test-lookup independent of prior commits<commit_after>use crate::index::index_ro;
use crates_index_diff::{Change, CrateVersion, Index};
use git_repository as git;

#[test]
fn addition() -> crate::Result {
    let changes = changes(index_ro()?, ":/initial commit")?;
    assert_eq!(changes.len(), 3228);
    assert!(matches!(
        changes
            .first()
            .and_then(|c| c.added().map(|v| v.name.as_str())),
        Some("gi-get-artifact")
    ));
    assert!(matches!(
        changes.last().expect("present"),
        Change::Added(CrateVersion {name, ..}) if name == "gizmo"
    ));
    Ok(())
}

#[test]
fn deletion() -> crate::Result {
    let changes = changes(index_ro()?, "@~^{/Updating crate `git-shell#0.3.0`}~1")?;
    assert_eq!(changes.len(), 1);
    assert_eq!(changes.first().and_then(|c| c.deleted()), Some("girl"));
    Ok(())
}

#[test]
fn new_version() -> crate::Result {
    let changes = changes(index_ro()?, ":/Updating crate `git-repository#0.22.1`")?;
    assert_eq!(changes.len(), 1);
    assert_eq!(
        changes
            .first()
            .and_then(|c| c.added().map(|v| v.name.as_str())),
        Some("git-repository")
    );
    Ok(())
}

#[test]
fn yanked() -> crate::Result {
    let changes = changes(index_ro()?, ":/Yanking crate `github_release_rs#0.1.0`")?;
    assert_eq!(changes.len(), 1);
    assert_eq!(
        changes
            .first()
            .and_then(|c| c.yanked().map(|v| v.name.as_str())),
        Some("github_release_rs")
    );
    Ok(())
}

#[test]
fn yanked_in_new_file() -> crate::Result {
    let changes = changes(index_ro()?, ":/reproduce issue #19")?;
    assert_eq!(changes.len(), 1);
    assert_eq!(
        changes
            .first()
            .and_then(|c| c.yanked().map(|v| v.name.as_str())),
        Some("allowed")
    );
    Ok(())
}

#[test]
fn unyanked_crates_recognized_as_added() -> crate::Result {
    let changes = changes(index_ro()?, ":/Unyanking crate `git2mail#0.3.2`")?;
    assert_eq!(changes.len(), 1);
    assert_eq!(
        changes
            .first()
            .and_then(|c| c.added().map(|v| v.name.as_str())),
        Some("git2mail")
    );
    Ok(())
}

#[test]
fn normalization() -> crate::Result {
    let changes = changes(index_ro()?, ":/normalize")?;
    assert_eq!(
        changes.len(),
        0,
        "normalization changes the representation, but the data itself stays the same"
    );
    Ok(())
}

fn changes(mut index: Index, revspec: &str) -> crate::Result<Vec<Change>> {
    let (prev, current) = {
        let repo = index.repository_mut();
        repo.object_cache_size_if_unset(4 * 1024 * 1024);
        let commit = repo.rev_parse(revspec)?.single().unwrap();
        let ancestor_tree = commit
            .object()?
            .into_commit()
            .parent_ids()
            .next()
            .and_then(|parent| {
                parent
                    .object()
                    .ok()?
                    .into_commit()
                    .tree_id()
                    .ok()
                    .map(|id| id.detach())
            })
            .unwrap_or_else(|| git::hash::ObjectId::empty_tree(repo.object_hash()));
        (ancestor_tree, commit.detach())
    };
    Ok(index.changes_between_commits(prev, current)?)
}
<|endoftext|>


<commit_before>extern crate glutin;

pub struct CameraState {
    aspect_ratio: f32,
    position: (f32, f32, f32),
    direction: (f32, f32, f32),

    moving_up: bool,
    moving_left: bool,
    moving_down: bool,
    moving_right: bool,
    moving_forward: bool,
    moving_backward: bool,
}

impl CameraState {
    pub fn new() -> CameraState {
        CameraState {
            aspect_ratio: 1024.0 / 768.0,
            position: (0.1, 0.1, 1.0),
            direction: (0.0, 0.0, 1.0),
            moving_up: false,
            moving_left: false,
            moving_down: false,
            moving_right: false,
            moving_forward: false,
            moving_backward: false,
        }
    }

    pub fn set_position(&mut self, pos: (f32, f32, f32)) {
        self.position = pos;
    }

    pub fn set_direction(&mut self, dir: (f32, f32, f32)) {
        self.direction = dir;
    }

    pub fn get_perspective(&self) -> [[f32; 4]; 4] {
        let fov: f32 = 3.141592 / 2.0;
        let zfar = 1024.0;
        let znear = 0.1;

        let f = 1.0 / (fov / 2.0).tan();

        // note: remember that this is column-major, so the lines of code are actually columns
        [
            [f / self.aspect_ratio,    0.0,              0.0              ,   0.0],
            [         0.0         ,     f ,              0.0              ,   0.0],
            [         0.0         ,    0.0,  (zfar+znear)/(znear-zfar)    ,  -1.0],
            [         0.0         ,    0.0,  (2.0*zfar*znear)/(znear-zfar),   0.0],
        ]
    }

    pub fn get_view(&self) -> [[f32; 4]; 4] {
        let f = {
            let f = self.direction;
            let len = f.0 * f.0 + f.1 * f.1 + f.2 * f.2;
            let len = len.sqrt();
            (f.0 / len, f.1 / len, f.2 / len)
        };

        let up = (0.0, 1.0, 0.0);

        let s = (f.1 * up.2 - f.2 * up.1,
                 f.2 * up.0 - f.0 * up.2,
                 f.0 * up.1 - f.1 * up.0);

        let s_norm = {
            let len = s.0 * s.0 + s.1 * s.1 + s.2 * s.2;
            let len = len.sqrt();
            (s.0 / len, s.1 / len, s.2 / len)
        };

        let u = (s_norm.1 * f.2 - s_norm.2 * f.1,
                 s_norm.2 * f.0 - s_norm.0 * f.2,
                 s_norm.0 * f.1 - s_norm.1 * f.0);

        let p = (-self.position.0 * s.0 - self.position.1 * s.1 - self.position.2 * s.2,
                 -self.position.0 * u.0 - self.position.1 * u.1 - self.position.2 * u.2,
                 -self.position.0 * f.0 - self.position.1 * f.1 - self.position.2 * f.2);

        // note: remember that this is column-major, so the lines of code are actually columns
        [
            [s_norm.0, u.0, -f.0, 0.0],
            [s_norm.1, u.1, -f.1, 0.0],
            [s_norm.2, u.2, -f.2, 0.0],
            [p.0, p.1,  p.2, 1.0],
        ]
    }

    pub fn update(&mut self) {
        let f = {
            let f = self.direction;
            let len = f.0 * f.0 + f.1 * f.1 + f.2 * f.2;
            let len = len.sqrt();
            (f.0 / len, f.1 / len, f.2 / len)
        };

        let up = (0.0, 1.0, 0.0);

        let s = (f.1 * up.2 - f.2 * up.1,
                 f.2 * up.0 - f.0 * up.2,
                 f.0 * up.1 - f.1 * up.0);

        let s = {
            let len = s.0 * s.0 + s.1 * s.1 + s.2 * s.2;
            let len = len.sqrt();
            (s.0 / len, s.1 / len, s.2 / len)
        };

        let u = (s.1 * f.2 - s.2 * f.1,
                 s.2 * f.0 - s.0 * f.2,
                 s.0 * f.1 - s.1 * f.0);

        if self.moving_up {
            self.position.0 += u.0 * 0.01;
            self.position.1 += u.1 * 0.01;
            self.position.2 += u.2 * 0.01;
        }

        if self.moving_left {
            self.position.0 -= s.0 * 0.01;
            self.position.1 -= s.1 * 0.01;
            self.position.2 -= s.2 * 0.01;
        }

        if self.moving_down {
            self.position.0 -= u.0 * 0.01;
            self.position.1 -= u.1 * 0.01;
            self.position.2 -= u.2 * 0.01;
        }

        if self.moving_right {
            self.position.0 += s.0 * 0.01;
            self.position.1 += s.1 * 0.01;
            self.position.2 += s.2 * 0.01;
        }

        if self.moving_forward {
            // TODO: to be honest, I don't understand why this is the wrong way
            self.position.0 -= f.0 * 0.01;
            self.position.1 -= f.1 * 0.01;
            self.position.2 -= f.2 * 0.01;
        }

        if self.moving_backward {
            // TODO: to be honest, I don't understand why this is the wrong way
            self.position.0 += f.0 * 0.01;
            self.position.1 += f.1 * 0.01;
            self.position.2 += f.2 * 0.01;
        }
    }

    pub fn process_input(&mut self, event: &glutin::Event) {
        match event {
            &glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(glutin::VirtualKeyCode::Space)) => {
                self.moving_up = true;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Released, _, Some(glutin::VirtualKeyCode::Space)) => {
                self.moving_up = false;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(glutin::VirtualKeyCode::Down)) => {
                self.moving_down = true;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Released, _, Some(glutin::VirtualKeyCode::Down)) => {
                self.moving_down = false;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(glutin::VirtualKeyCode::A)) => {
                self.moving_left = true;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Released, _, Some(glutin::VirtualKeyCode::A)) => {
                self.moving_left = false;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(glutin::VirtualKeyCode::D)) => {
                self.moving_right = true;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Released, _, Some(glutin::VirtualKeyCode::D)) => {
                self.moving_right = false;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(glutin::VirtualKeyCode::W)) => {
                self.moving_forward = true;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Released, _, Some(glutin::VirtualKeyCode::W)) => {
                self.moving_forward = false;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(glutin::VirtualKeyCode::S)) => {
                self.moving_backward = true;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Released, _, Some(glutin::VirtualKeyCode::S)) => {
                self.moving_backward = false;
            },
            _ => {}
        }
    }
}
<commit_msg>Fixing camera.rs of the example<commit_after>extern crate glutin;

pub struct CameraState {
    aspect_ratio: f32,
    position: (f32, f32, f32),
    direction: (f32, f32, f32),

    moving_up: bool,
    moving_left: bool,
    moving_down: bool,
    moving_right: bool,
    moving_forward: bool,
    moving_backward: bool,
}

impl CameraState {
    pub fn new() -> CameraState {
        CameraState {
            aspect_ratio: 1024.0 / 768.0,
            position: (0.1, 0.1, 1.0),
            direction: (0.0, 0.0, -1.0),
            moving_up: false,
            moving_left: false,
            moving_down: false,
            moving_right: false,
            moving_forward: false,
            moving_backward: false,
        }
    }

    pub fn set_position(&mut self, pos: (f32, f32, f32)) {
        self.position = pos;
    }

    pub fn set_direction(&mut self, dir: (f32, f32, f32)) {
        self.direction = dir;
    }

    pub fn get_perspective(&self) -> [[f32; 4]; 4] {
        let fov: f32 = 3.141592 / 2.0;
        let zfar = 1024.0;
        let znear = 0.1;

        let f = 1.0 / (fov / 2.0).tan();

        // note: remember that this is column-major, so the lines of code are actually columns
        [
            [f / self.aspect_ratio,    0.0,              0.0              ,   0.0],
            [         0.0         ,     f ,              0.0              ,   0.0],
            [         0.0         ,    0.0,  (zfar+znear)/(zfar-znear)    ,   1.0],
            [         0.0         ,    0.0, -(2.0*zfar*znear)/(zfar-znear),   0.0],
        ]
    }

    pub fn get_view(&self) -> [[f32; 4]; 4] {
        let f = {
            let f = self.direction;
            let len = f.0 * f.0 + f.1 * f.1 + f.2 * f.2;
            let len = len.sqrt();
            (f.0 / len, f.1 / len, f.2 / len)
        };

        let up = (0.0, 1.0, 0.0);

        let s = (f.1 * up.2 - f.2 * up.1,
                 f.2 * up.0 - f.0 * up.2,
                 f.0 * up.1 - f.1 * up.0);

        let s_norm = {
            let len = s.0 * s.0 + s.1 * s.1 + s.2 * s.2;
            let len = len.sqrt();
            (s.0 / len, s.1 / len, s.2 / len)
        };

        let u = (s_norm.1 * f.2 - s_norm.2 * f.1,
                 s_norm.2 * f.0 - s_norm.0 * f.2,
                 s_norm.0 * f.1 - s_norm.1 * f.0);

        let p = (-self.position.0 * s.0 - self.position.1 * s.1 - self.position.2 * s.2,
                 -self.position.0 * u.0 - self.position.1 * u.1 - self.position.2 * u.2,
                 -self.position.0 * f.0 - self.position.1 * f.1 - self.position.2 * f.2);

        // note: remember that this is column-major, so the lines of code are actually columns
        [
            [s_norm.0, u.0, f.0, 0.0],
            [s_norm.1, u.1, f.1, 0.0],
            [s_norm.2, u.2, f.2, 0.0],
            [p.0, p.1,  p.2, 1.0],
        ]
    }

    pub fn update(&mut self) {
        let f = {
            let f = self.direction;
            let len = f.0 * f.0 + f.1 * f.1 + f.2 * f.2;
            let len = len.sqrt();
            (f.0 / len, f.1 / len, f.2 / len)
        };

        let up = (0.0, 1.0, 0.0);

        let s = (f.1 * up.2 - f.2 * up.1,
                 f.2 * up.0 - f.0 * up.2,
                 f.0 * up.1 - f.1 * up.0);

        let s = {
            let len = s.0 * s.0 + s.1 * s.1 + s.2 * s.2;
            let len = len.sqrt();
            (s.0 / len, s.1 / len, s.2 / len)
        };

        let u = (s.1 * f.2 - s.2 * f.1,
                 s.2 * f.0 - s.0 * f.2,
                 s.0 * f.1 - s.1 * f.0);

        if self.moving_up {
            self.position.0 += u.0 * 0.01;
            self.position.1 += u.1 * 0.01;
            self.position.2 += u.2 * 0.01;
        }

        if self.moving_left {
            self.position.0 -= s.0 * 0.01;
            self.position.1 -= s.1 * 0.01;
            self.position.2 -= s.2 * 0.01;
        }

        if self.moving_down {
            self.position.0 -= u.0 * 0.01;
            self.position.1 -= u.1 * 0.01;
            self.position.2 -= u.2 * 0.01;
        }

        if self.moving_right {
            self.position.0 += s.0 * 0.01;
            self.position.1 += s.1 * 0.01;
            self.position.2 += s.2 * 0.01;
        }

        if self.moving_forward {
            self.position.0 += f.0 * 0.01;
            self.position.1 += f.1 * 0.01;
            self.position.2 += f.2 * 0.01;
        }

        if self.moving_backward {
            self.position.0 -= f.0 * 0.01;
            self.position.1 -= f.1 * 0.01;
            self.position.2 -= f.2 * 0.01;
        }
    }

    pub fn process_input(&mut self, event: &glutin::Event) {
        match event {
            &glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(glutin::VirtualKeyCode::Space)) => {
                self.moving_up = true;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Released, _, Some(glutin::VirtualKeyCode::Space)) => {
                self.moving_up = false;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(glutin::VirtualKeyCode::Down)) => {
                self.moving_down = true;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Released, _, Some(glutin::VirtualKeyCode::Down)) => {
                self.moving_down = false;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(glutin::VirtualKeyCode::A)) => {
                self.moving_left = true;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Released, _, Some(glutin::VirtualKeyCode::A)) => {
                self.moving_left = false;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(glutin::VirtualKeyCode::D)) => {
                self.moving_right = true;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Released, _, Some(glutin::VirtualKeyCode::D)) => {
                self.moving_right = false;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(glutin::VirtualKeyCode::W)) => {
                self.moving_forward = true;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Released, _, Some(glutin::VirtualKeyCode::W)) => {
                self.moving_forward = false;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(glutin::VirtualKeyCode::S)) => {
                self.moving_backward = true;
            },
            &glutin::Event::KeyboardInput(glutin::ElementState::Released, _, Some(glutin::VirtualKeyCode::S)) => {
                self.moving_backward = false;
            },
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>pub mod requests;
pub use requests::*;

pub use telegram_bot_raw::{Integer, Float, True, Request};
pub use telegram_bot_raw::{Update, UpdateKind, RawUpdate};
pub use telegram_bot_raw::{User, Group, Supergroup, Channel, Chat, RawChat};
pub use telegram_bot_raw::{Message, MessageKind, RawMessage, Forward, ForwardFrom};
pub use telegram_bot_raw::{MessageEntity, MessageEntityKind, RawMessageEntity};
pub use telegram_bot_raw::{Audio, Document, PhotoSize, Sticker, Video, Voice};
pub use telegram_bot_raw::{Contact, Location, Venue};

pub use telegram_bot_raw::{ParseMode, ChatId, UserId, MessageId};
pub use telegram_bot_raw::{ReplyMarkup, InlineKeyboardMarkup, ReplyKeyboardMarkup};
pub use telegram_bot_raw::{ReplyKeyboardRemove, ForceReply};
pub use telegram_bot_raw::{ChatAction};
<commit_msg>refactor: do not export raw types in telegram-bot<commit_after>pub mod requests;
pub use requests::*;

pub use telegram_bot_raw::{Integer, Float, True, Request};
pub use telegram_bot_raw::{Update, UpdateKind};
pub use telegram_bot_raw::{User, Group, Supergroup, Channel, Chat};
pub use telegram_bot_raw::{Message, MessageKind, Forward, ForwardFrom};
pub use telegram_bot_raw::{MessageEntity, MessageEntityKind};
pub use telegram_bot_raw::{Audio, Document, PhotoSize, Sticker, Video, Voice};
pub use telegram_bot_raw::{Contact, Location, Venue};

pub use telegram_bot_raw::{ParseMode, ChatId, UserId, MessageId};
pub use telegram_bot_raw::{ReplyMarkup, InlineKeyboardMarkup, ReplyKeyboardMarkup};
pub use telegram_bot_raw::{ReplyKeyboardRemove, ForceReply};
pub use telegram_bot_raw::{ChatAction};
<|endoftext|>


<commit_before>use std::io::{Read};
use std::io;
use std::env;
use std::string::{String};
use std::fs::File;
use std::vec;
use std::collections::HashMap;

const CHUNK: usize = 4192;

fn get_pushed_data(data: Vec<u8>) -> HashMap<String, String>
{
	let mut buf = data;
	let mut i = 0;
	let mut parameters = HashMap::new();

	while i < buf.len()
	{
		let mut name: String = String::new();
		let mut data: String = String::new();

		while buf[i] as char != '='
		{
			name.push(buf[i] as char);
			i += 1;
		}

		while buf[i] as char != '&'
		{
			data.push(buf[i] as char);
			i += 1;
		}

		parameters.insert(name, data);
	}

	return parameters;
}

fn get_http_request() {
	let mut method = env::var("REQUEST_METHOD").unwrap();
	let mut contents: Vec<u8> = Vec::new();

	match method.as_ref()
	{
		"POST" =>
		{
			method = env::var("CONTENT_LENGTH").unwrap();
			let mut total: usize = method.trim().parse().unwrap();
			let mut buf = [0u8; CHUNK];

			let mut current = 0;

			let mut stream = io::stdin(); //File::open("/dev/stdin").unwrap();
			while current < total
			{
				let bytes = stream.read(&mut buf[0..CHUNK]).unwrap();
				current += bytes;

				for byte in buf.iter() {
					contents.push(*byte);
				}
			}

		}

		"GET" =>
		{
			let query_string = env::var("QUERY_STRING").unwrap();

			for byte in query_string.as_bytes()
			{
				contents.push(*byte);
			}

		}

		_ =>
		{

		}
	}

	let mut params = get_pushed_data(contents);
}

fn main() {
    get_http_request();

    println!("Content-Type: text/html\r\n\r\n");
    println!("
hi
");

}
<commit_msg>tired, fix tomorrow!<commit_after>use std::io::{Read};
use std::io;
use std::env;
use std::string::{String};
use std::fs::File;
use std::vec;
use std::collections::HashMap;

const CHUNK: usize = 4192;

fn get_pushed_data(data: Vec<u8>, length: usize) -> HashMap<String, String>
{
	let mut buf = data;
	let mut i = 0;
	let mut parameters = HashMap::new();

	while i < length
	{
		let mut name: String = String::new();
		let mut data: String = String::new();

		while buf[i] as char != '='
		{
			name.push(buf[i] as char);
			i += 1;
		}

		i += 1;

		while buf[i] as char != '&'
		{
			data.push(buf[i] as char);
			i += 1;
		}
		println!("
{} and {}
", name, data);
		parameters.insert(name, data);
	}

	return parameters;
}

fn get_http_request() -> HashMap<String,String> {
	let mut method = env::var("REQUEST_METHOD").unwrap();
	let mut contents: Vec<u8> = Vec::new();
	let mut length = 0;

	match method.as_ref()
	{
		"POST" =>
		{
			method = env::var("CONTENT_LENGTH").unwrap();
			let mut total: usize = method.trim().parse().unwrap();
			let mut buf = [0u8; CHUNK];

			let mut current = 0;

			let mut stream = io::stdin(); //File::open("/dev/stdin").unwrap();
			while current < total
			{
				let bytes = stream.read(&mut buf[0..CHUNK]).unwrap();
				current += bytes;

				for byte in buf.iter() {
					contents.push(*byte);
					length += 1;
				}
			}

			println!("
POST
");

		}

		"GET" =>
		{
			let query_string = env::var("QUERY_STRING").unwrap();

			for byte in query_string.as_bytes()
			{
				contents.push(*byte);
				length += 1;
			}

		}

		_ =>
		{

		}
	}

	get_pushed_data(contents, length)
}

fn main() {
	println!("Content-Type: text/html\r\n\r\n");
 	println!("
hi
");

	let mut params: HashMap<String,String> = get_http_request();
	for (name, value) in params.iter()
	{
		println!("
{} and {}
", name, value);
	}
	println!("
DONE!
");
}
<|endoftext|>


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

use core::fmt;
use core::hash::{Hash, Hasher};
use core::ptr;
use core::str;

use crate::position;

/// A span over a `&str`. It is created from either [two `Position`s] or from a [`Pair`].
///
/// [two `Position`s]: struct.Position.html#method.span
/// [`Pair`]: ../iterators/struct.Pair.html#method.span
#[derive(Clone, Copy)]
pub struct Span<'i> {
    input: &'i str,
    /// # Safety
    ///
    /// Must be a valid character boundary index into `input`.
    start: usize,
    /// # Safety
    ///
    /// Must be a valid character boundary index into `input`.
    end: usize,
}

impl<'i> Span<'i> {
    /// Create a new `Span` without checking invariants. (Checked with `debug_assertions`.)
    ///
    /// # Safety
    ///
    /// `input[start..end]` must be a valid subslice; that is, said indexing should not panic.
    pub(crate) unsafe fn new_unchecked(input: &str, start: usize, end: usize) -> Span {
        debug_assert!(input.get(start..end).is_some());
        Span { input, start, end }
    }

    /// Attempts to create a new span. Will return `None` if `input[start..end]` is an invalid index
    /// into `input`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Span;
    /// let input = "Hello!";
    /// assert_eq!(None, Span::new(input, 100, 0));
    /// assert!(Span::new(input, 0, input.len()).is_some());
    /// ```
    pub fn new(input: &str, start: usize, end: usize) -> Option<Span> {
        if input.get(start..end).is_some() {
            Some(Span { input, start, end })
        } else {
            None
        }
    }

    /// Returns the `Span`'s start byte position as a `usize`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.start(), 0);
    /// ```
    #[inline]
    pub fn start(&self) -> usize {
        self.start
    }

    /// Returns the `Span`'s end byte position as a `usize`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.end(), 0);
    /// ```
    #[inline]
    pub fn end(&self) -> usize {
        self.end
    }

    /// Returns the `Span`'s start `Position`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.clone().span(&end);
    ///
    /// assert_eq!(span.start_pos(), start);
    /// ```
    #[inline]
    pub fn start_pos(&self) -> position::Position<'i> {
        // Span's start position is always a UTF-8 border.
        unsafe { position::Position::new_unchecked(self.input, self.start) }
    }

    /// Returns the `Span`'s end `Position`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.end_pos(), end);
    /// ```
    #[inline]
    pub fn end_pos(&self) -> position::Position<'i> {
        // Span's end position is always a UTF-8 border.
        unsafe { position::Position::new_unchecked(self.input, self.end) }
    }

    /// Splits the `Span` into a pair of `Position`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.clone().span(&end);
    ///
    /// assert_eq!(span.split(), (start, end));
    /// ```
    #[inline]
    pub fn split(self) -> (position::Position<'i>, position::Position<'i>) {
        // Span's start and end positions are always a UTF-8 borders.
        let pos1 = unsafe { position::Position::new_unchecked(self.input, self.start) };
        let pos2 = unsafe { position::Position::new_unchecked(self.input, self.end) };

        (pos1, pos2)
    }

    /// Captures a slice from the `&str` defined by the `Span`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {}
    ///
    /// let input = "abc";
    /// let mut state: Box<pest::ParserState<Rule>> = pest::ParserState::new(input).skip(1).unwrap();
    /// let start_pos = state.position().clone();
    /// state = state.match_string("b").unwrap();
    /// let span = start_pos.span(&state.position().clone());
    /// assert_eq!(span.as_str(), "b");
    /// ```
    #[inline]
    pub fn as_str(&self) -> &'i str {
        // Span's start and end positions are always a UTF-8 borders.
        &self.input[self.start..self.end]
    }

    /// Iterates over all lines (partially) covered by this span.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {}
    ///
    /// let input = "a\nb\nc";
    /// let mut state: Box<pest::ParserState<Rule>> = pest::ParserState::new(input).skip(2).unwrap();
    /// let start_pos = state.position().clone();
    /// state = state.match_string("b\nc").unwrap();
    /// let span = start_pos.span(&state.position().clone());
    /// assert_eq!(span.lines().collect::<Vec<_>>(), vec!["b\n", "c"]);
    /// ```
    #[inline]
    pub fn lines(&self) -> Lines {
        Lines {
            span: self,
            pos: self.start,
        }
    }
}

impl<'i> fmt::Debug for Span<'i> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Span")
            .field("str", &self.as_str())
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

impl<'i> PartialEq for Span<'i> {
    fn eq(&self, other: &Span<'i>) -> bool {
        ptr::eq(self.input, other.input) && self.start == other.start && self.end == other.end
    }
}

impl<'i> Eq for Span<'i> {}

impl<'i> Hash for Span<'i> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (self.input as *const str).hash(state);
        self.start.hash(state);
        self.end.hash(state);
    }
}

/// Line iterator for Spans, created by [`Span::lines()`].
///
/// Iterates all lines that are at least partially covered by the span.
///
/// [`Span::lines()`]: struct.Span.html#method.lines
pub struct Lines<'i> {
    span: &'i Span<'i>,
    pos: usize,
}

impl<'i> Iterator for Lines<'i> {
    type Item = &'i str;
    fn next(&mut self) -> Option<&'i str> {
        if self.pos > self.span.end {
            return None;
        }
        let pos = position::Position::new(self.span.input, self.pos)?;
        if pos.at_end() {
            return None;
        }
        let line = pos.line_of();
        self.pos = pos.find_line_end();
        Some(line)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use alloc::borrow::ToOwned;
    use alloc::vec::Vec;

    #[test]
    fn span_comp() {
        let input = "abc\ndef\nghi";
        let span = Span::new(input, 1, 7).unwrap();
        let span2 = Span::new(input, 50, 51);
        assert!(span2.is_none());
        let span3 = Span::new(input, 0, 8).unwrap();
        assert!(span != span3);
    }

    #[test]
    fn split() {
        let input = "a";
        let start = position::Position::from_start(input);
        let mut end = start;

        assert!(end.skip(1));

        let span = start.clone().span(&end.clone());

        assert_eq!(span.split(), (start, end));
    }

    #[test]
    fn lines_mid() {
        let input = "abc\ndef\nghi";
        let span = Span::new(input, 1, 7).unwrap();
        let lines: Vec<_> = span.lines().collect();
        //println!("{:?}", lines);
        assert_eq!(lines.len(), 2);
        assert_eq!(lines[0], "abc\n".to_owned());
        assert_eq!(lines[1], "def\n".to_owned());
    }

    #[test]
    fn lines_eof() {
        let input = "abc\ndef\nghi";
        let span = Span::new(input, 5, 11).unwrap();
        assert!(span.end_pos().at_end());
        assert_eq!(span.end(), 11);
        let lines: Vec<_> = span.lines().collect();
        //println!("{:?}", lines);
        assert_eq!(lines.len(), 2);
        assert_eq!(lines[0], "def\n".to_owned());
        assert_eq!(lines[1], "ghi".to_owned());
    }
}
<commit_msg>Implement `Span::get` (#681)<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use core::fmt;
use core::hash::{Hash, Hasher};
use core::ops::{Bound, RangeBounds};
use core::ptr;
use core::str;

use crate::position;

/// A span over a `&str`. It is created from either [two `Position`s] or from a [`Pair`].
///
/// [two `Position`s]: struct.Position.html#method.span
/// [`Pair`]: ../iterators/struct.Pair.html#method.span
#[derive(Clone, Copy)]
pub struct Span<'i> {
    input: &'i str,
    /// # Safety
    ///
    /// Must be a valid character boundary index into `input`.
    start: usize,
    /// # Safety
    ///
    /// Must be a valid character boundary index into `input`.
    end: usize,
}

impl<'i> Span<'i> {
    /// Create a new `Span` without checking invariants. (Checked with `debug_assertions`.)
    ///
    /// # Safety
    ///
    /// `input[start..end]` must be a valid subslice; that is, said indexing should not panic.
    pub(crate) unsafe fn new_unchecked(input: &str, start: usize, end: usize) -> Span {
        debug_assert!(input.get(start..end).is_some());
        Span { input, start, end }
    }

    /// Attempts to create a new span. Will return `None` if `input[start..end]` is an invalid index
    /// into `input`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Span;
    /// let input = "Hello!";
    /// assert_eq!(None, Span::new(input, 100, 0));
    /// assert!(Span::new(input, 0, input.len()).is_some());
    /// ```
    pub fn new(input: &str, start: usize, end: usize) -> Option<Span> {
        if input.get(start..end).is_some() {
            Some(Span { input, start, end })
        } else {
            None
        }
    }

    /// Attempts to create a new span based on a sub-range.
    ///
    /// ```
    /// use pest::Span;
    /// let input = "Hello World!";
    /// let world = Span::new(input, 6, input.len()).unwrap();
    /// let orl = world.get(1..=3);
    /// assert!(orl.is_some());
    /// assert_eq!(orl.unwrap().as_str(), "orl");
    /// ```
    ///
    /// # Examples
    pub fn get(&self, range: impl RangeBounds<usize>) -> Option<Span<'i>> {
        let start = match range.start_bound() {
            Bound::Included(offset) => *offset,
            Bound::Excluded(offset) => *offset + 1,
            Bound::Unbounded => 0,
        };
        let end = match range.end_bound() {
            Bound::Included(offset) => *offset + 1,
            Bound::Excluded(offset) => *offset,
            Bound::Unbounded => self.as_str().len(),
        };

        self.as_str().get(start..end).map(|_| Span {
            input: self.input,
            start: self.start + start,
            end: self.start + end,
        })
    }

    /// Returns the `Span`'s start byte position as a `usize`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.start(), 0);
    /// ```
    #[inline]
    pub fn start(&self) -> usize {
        self.start
    }

    /// Returns the `Span`'s end byte position as a `usize`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.end(), 0);
    /// ```
    #[inline]
    pub fn end(&self) -> usize {
        self.end
    }

    /// Returns the `Span`'s start `Position`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.clone().span(&end);
    ///
    /// assert_eq!(span.start_pos(), start);
    /// ```
    #[inline]
    pub fn start_pos(&self) -> position::Position<'i> {
        // Span's start position is always a UTF-8 border.
        unsafe { position::Position::new_unchecked(self.input, self.start) }
    }

    /// Returns the `Span`'s end `Position`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.end_pos(), end);
    /// ```
    #[inline]
    pub fn end_pos(&self) -> position::Position<'i> {
        // Span's end position is always a UTF-8 border.
        unsafe { position::Position::new_unchecked(self.input, self.end) }
    }

    /// Splits the `Span` into a pair of `Position`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.clone().span(&end);
    ///
    /// assert_eq!(span.split(), (start, end));
    /// ```
    #[inline]
    pub fn split(self) -> (position::Position<'i>, position::Position<'i>) {
        // Span's start and end positions are always a UTF-8 borders.
        let pos1 = unsafe { position::Position::new_unchecked(self.input, self.start) };
        let pos2 = unsafe { position::Position::new_unchecked(self.input, self.end) };

        (pos1, pos2)
    }

    /// Captures a slice from the `&str` defined by the `Span`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {}
    ///
    /// let input = "abc";
    /// let mut state: Box<pest::ParserState<Rule>> = pest::ParserState::new(input).skip(1).unwrap();
    /// let start_pos = state.position().clone();
    /// state = state.match_string("b").unwrap();
    /// let span = start_pos.span(&state.position().clone());
    /// assert_eq!(span.as_str(), "b");
    /// ```
    #[inline]
    pub fn as_str(&self) -> &'i str {
        // Span's start and end positions are always a UTF-8 borders.
        &self.input[self.start..self.end]
    }

    /// Iterates over all lines (partially) covered by this span.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {}
    ///
    /// let input = "a\nb\nc";
    /// let mut state: Box<pest::ParserState<Rule>> = pest::ParserState::new(input).skip(2).unwrap();
    /// let start_pos = state.position().clone();
    /// state = state.match_string("b\nc").unwrap();
    /// let span = start_pos.span(&state.position().clone());
    /// assert_eq!(span.lines().collect::<Vec<_>>(), vec!["b\n", "c"]);
    /// ```
    #[inline]
    pub fn lines(&self) -> Lines {
        Lines {
            span: self,
            pos: self.start,
        }
    }
}

impl<'i> fmt::Debug for Span<'i> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Span")
            .field("str", &self.as_str())
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

impl<'i> PartialEq for Span<'i> {
    fn eq(&self, other: &Span<'i>) -> bool {
        ptr::eq(self.input, other.input) && self.start == other.start && self.end == other.end
    }
}

impl<'i> Eq for Span<'i> {}

impl<'i> Hash for Span<'i> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (self.input as *const str).hash(state);
        self.start.hash(state);
        self.end.hash(state);
    }
}

/// Line iterator for Spans, created by [`Span::lines()`].
///
/// Iterates all lines that are at least partially covered by the span.
///
/// [`Span::lines()`]: struct.Span.html#method.lines
pub struct Lines<'i> {
    span: &'i Span<'i>,
    pos: usize,
}

impl<'i> Iterator for Lines<'i> {
    type Item = &'i str;
    fn next(&mut self) -> Option<&'i str> {
        if self.pos > self.span.end {
            return None;
        }
        let pos = position::Position::new(self.span.input, self.pos)?;
        if pos.at_end() {
            return None;
        }
        let line = pos.line_of();
        self.pos = pos.find_line_end();
        Some(line)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use alloc::borrow::ToOwned;
    use alloc::vec::Vec;

    #[test]
    fn get() {
        let input = "abc123abc";
        let span = Span::new(input, 3, input.len()).unwrap();
        assert_eq!(span.as_str(), "123abc");
        assert_eq!(span.input, input);

        let span1 = span.get(..=2);
        assert!(span1.is_some());
        assert_eq!(span1.unwrap().input, input);
        assert_eq!(span1.unwrap().as_str(), "123");

        let span2 = span.get(..);
        assert!(span2.is_some());
        assert_eq!(span2.unwrap().input, input);
        assert_eq!(span2.unwrap().as_str(), "123abc");

        let span3 = span.get(3..);
        assert!(span3.is_some());
        assert_eq!(span3.unwrap().input, input);
        assert_eq!(span3.unwrap().as_str(), "abc");

        let span4 = span.get(0..0);
        assert!(span4.is_some());
        assert_eq!(span4.unwrap().input, input);
        assert_eq!(span4.unwrap().as_str(), "");
    }

    #[test]
    fn get_fails() {
        let input = "abc";
        let span = Span::new(input, 0, input.len()).unwrap();

        let span1 = span.get(0..100);
        assert!(span1.is_none());

        let span2 = span.get(100..200);
        assert!(span2.is_none());
    }

    #[test]
    fn span_comp() {
        let input = "abc\ndef\nghi";
        let span = Span::new(input, 1, 7).unwrap();
        let span2 = Span::new(input, 50, 51);
        assert!(span2.is_none());
        let span3 = Span::new(input, 0, 8).unwrap();
        assert!(span != span3);
    }

    #[test]
    fn split() {
        let input = "a";
        let start = position::Position::from_start(input);
        let mut end = start;

        assert!(end.skip(1));

        let span = start.clone().span(&end.clone());

        assert_eq!(span.split(), (start, end));
    }

    #[test]
    fn lines_mid() {
        let input = "abc\ndef\nghi";
        let span = Span::new(input, 1, 7).unwrap();
        let lines: Vec<_> = span.lines().collect();
        //println!("{:?}", lines);
        assert_eq!(lines.len(), 2);
        assert_eq!(lines[0], "abc\n".to_owned());
        assert_eq!(lines[1], "def\n".to_owned());
    }

    #[test]
    fn lines_eof() {
        let input = "abc\ndef\nghi";
        let span = Span::new(input, 5, 11).unwrap();
        assert!(span.end_pos().at_end());
        assert_eq!(span.end(), 11);
        let lines: Vec<_> = span.lines().collect();
        //println!("{:?}", lines);
        assert_eq!(lines.len(), 2);
        assert_eq!(lines[0], "def\n".to_owned());
        assert_eq!(lines[1], "ghi".to_owned());
    }
}
<|endoftext|>


<commit_before>use super::*;

pub(crate) struct Context {
    // TODO file from config should be in here
    config: Config,
    pub(crate) pagecache: PageCache<BLinkMaterializer, Frag>,
}

impl std::ops::Deref for Context {
    type Target = Config;

    fn deref(&self) -> &Config {
        &self.config
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        if let Err(e) = self.pagecache.flush() {
            error!(
                "failed to flush underlying \
                 pagecache during drop: {:?}",
                e
            );
        }

        #[cfg(feature = "event_log")]
        {
            let guard = pin();

            self.config.event_log.meta_before_restart(
                meta::meta(&self.pagecache, &guard)
                    .expect("should get meta under test")
                    .clone(),
            );
        }
    }
}

impl Context {
    pub(crate) fn start(config: Config) -> Result<Context, ()> {
        #[cfg(any(test, feature = "check_snapshot_integrity"))]
        match config.verify_snapshot::<BLinkMaterializer, Frag>() {
            Ok(_) => {}
            #[cfg(feature = "failpoints")]
            Err(Error::FailPoint) => {}
            other => panic!("failed to verify snapshot: {:?}", other),
        }

        let pagecache = PageCache::start(config.clone())?;

        Ok(Context { config, pagecache })
    }

    /// Returns `true` if the database was
    /// recovered from a previous process.
    /// Note that database state is only
    /// guaranteed to be present up to the
    /// last call to `flush`! Otherwise state
    /// is synced to disk periodically if the
    /// `sync_every_ms` configuration option
    /// is set to `Some(number_of_ms_between_syncs)`
    /// or if the IO buffer gets filled to
    /// capacity before being rotated.
    pub fn was_recovered(&self) -> bool {
        self.pagecache.was_recovered()
    }

    /// Generate a monotonic ID. Not guaranteed to be
    /// contiguous. Written to disk every `idgen_persist_interval`
    /// operations, followed by a blocking flush. During recovery, we
    /// take the last recovered generated ID and add 2x
    /// the `idgen_persist_interval` to it. While persisting, if the
    /// previous persisted counter wasn't synced to disk yet, we will do
    /// a blocking flush to fsync the latest counter, ensuring
    /// that we will never give out the same counter twice.
    pub fn generate_id(&self) -> Result<u64, ()> {
        self.pagecache.generate_id()
    }
}
<commit_msg>Fix conditional event-log handling<commit_after>use super::*;

pub(crate) struct Context {
    // TODO file from config should be in here
    config: Config,
    pub(crate) pagecache: PageCache<BLinkMaterializer, Frag>,
}

impl std::ops::Deref for Context {
    type Target = Config;

    fn deref(&self) -> &Config {
        &self.config
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        if let Err(e) = self.pagecache.flush() {
            error!(
                "failed to flush underlying \
                 pagecache during drop: {:?}",
                e
            );
        }

        #[cfg(feature = "event_log")]
        {
            let guard = pin();

            self.config.event_log.meta_before_restart(
                self.pagecache
                    .meta(&guard)
                    .expect("should get meta under test")
                    .clone(),
            );
        }
    }
}

impl Context {
    pub(crate) fn start(config: Config) -> Result<Context, ()> {
        #[cfg(any(test, feature = "check_snapshot_integrity"))]
        match config.verify_snapshot::<BLinkMaterializer, Frag>() {
            Ok(_) => {}
            #[cfg(feature = "failpoints")]
            Err(Error::FailPoint) => {}
            other => panic!("failed to verify snapshot: {:?}", other),
        }

        let pagecache = PageCache::start(config.clone())?;

        Ok(Context { config, pagecache })
    }

    /// Returns `true` if the database was
    /// recovered from a previous process.
    /// Note that database state is only
    /// guaranteed to be present up to the
    /// last call to `flush`! Otherwise state
    /// is synced to disk periodically if the
    /// `sync_every_ms` configuration option
    /// is set to `Some(number_of_ms_between_syncs)`
    /// or if the IO buffer gets filled to
    /// capacity before being rotated.
    pub fn was_recovered(&self) -> bool {
        self.pagecache.was_recovered()
    }

    /// Generate a monotonic ID. Not guaranteed to be
    /// contiguous. Written to disk every `idgen_persist_interval`
    /// operations, followed by a blocking flush. During recovery, we
    /// take the last recovered generated ID and add 2x
    /// the `idgen_persist_interval` to it. While persisting, if the
    /// previous persisted counter wasn't synced to disk yet, we will do
    /// a blocking flush to fsync the latest counter, ensuring
    /// that we will never give out the same counter twice.
    pub fn generate_id(&self) -> Result<u64, ()> {
        self.pagecache.generate_id()
    }
}
<|endoftext|>