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

use ra_syntax::ast::{AstNode, RecordLit};

use super::{Expr, ExprId, RecordLitField};
use crate::{
    adt::AdtDef,
    diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr},
    expr::AstPtr,
    name,
    path::{PathKind, PathSegment},
    ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
    Function, HasSource, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution,
};
use ra_syntax::ast;

pub(crate) struct ExprValidator<'a, 'b: 'a> {
    func: Function,
    infer: Arc<InferenceResult>,
    sink: &'a mut DiagnosticSink<'b>,
}

impl<'a, 'b> ExprValidator<'a, 'b> {
    pub(crate) fn new(
        func: Function,
        infer: Arc<InferenceResult>,
        sink: &'a mut DiagnosticSink<'b>,
    ) -> ExprValidator<'a, 'b> {
        ExprValidator { func, infer, sink }
    }

    pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) {
        let body = self.func.body(db);

        for e in body.exprs() {
            if let (id, Expr::RecordLit { path, fields, spread }) = e {
                self.validate_record_literal(id, path, fields, *spread, db);
            }
        }

        let body_expr = &body[body.body_expr()];
        if let Expr::Block { statements: _, tail: Some(t) } = body_expr {
            self.validate_results_in_tail_expr(*t, db);
        }
    }

    fn validate_record_literal(
        &mut self,
        id: ExprId,
        _path: &Option<Path>,
        fields: &[RecordLitField],
        spread: Option<ExprId>,
        db: &impl HirDatabase,
    ) {
        if spread.is_some() {
            return;
        }

        let struct_def = match self.infer[id].as_adt() {
            Some((AdtDef::Struct(s), _)) => s,
            _ => return,
        };

        let lit_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
        let missed_fields: Vec<Name> = struct_def
            .fields(db)
            .iter()
            .filter_map(|f| {
                let name = f.name(db);
                if lit_fields.contains(&name) {
                    None
                } else {
                    Some(name)
                }
            })
            .collect();
        if missed_fields.is_empty() {
            return;
        }
        let source_map = self.func.body_source_map(db);
        let file_id = self.func.source(db).file_id;
        let parse = db.parse(file_id.original_file(db));
        let source_file = parse.tree();
        if let Some(field_list_node) = source_map
            .expr_syntax(id)
            .map(|ptr| ptr.to_node(source_file.syntax()))
            .and_then(RecordLit::cast)
            .and_then(|lit| lit.record_field_list())
        {
            let field_list_ptr = AstPtr::new(&field_list_node);
            self.sink.push(MissingFields {
                file: file_id,
                field_list: field_list_ptr,
                missed_fields,
            })
        }
    }

    fn validate_results_in_tail_expr(&mut self, id: ExprId, db: &impl HirDatabase) {
        let mismatch = match self.infer.type_mismatch_for_expr(id) {
            Some(m) => m,
            None => return,
        };

        let std_result_path = Path {
            kind: PathKind::Abs,
            segments: vec![
                PathSegment { name: name::STD, args_and_bindings: None },
                PathSegment { name: name::RESULT_MOD, args_and_bindings: None },
                PathSegment { name: name::RESULT_TYPE, args_and_bindings: None },
            ],
        };

        let resolver = self.func.resolver(db);
        let std_result_enum =
            match resolver.resolve_path_segments(db, &std_result_path).into_fully_resolved() {
                PerNs { types: Some(Resolution::Def(ModuleDef::Enum(e))), .. } => e,
                _ => return,
            };

        let std_result_ctor = TypeCtor::Adt(AdtDef::Enum(std_result_enum));
        let params = match &mismatch.expected {
            Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters,
            _ => return,
        };

        if params.len() == 2 && &params[0] == &mismatch.actual {
            let source_map = self.func.body_source_map(db);
            let file_id = self.func.source(db).file_id;

            if let Some(expr) = source_map.expr_syntax(id).and_then(|n| n.cast::<ast::Expr>()) {
                self.sink.push(MissingOkInTailExpr { file: file_id, expr });
            }
        }
    }
}
<commit_msg>Fix 'missing Ok in tail expr' validation<commit_after>use rustc_hash::FxHashSet;
use std::sync::Arc;

use ra_syntax::ast::{AstNode, RecordLit};

use super::{Expr, ExprId, RecordLitField};
use crate::{
    adt::AdtDef,
    diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr},
    expr::AstPtr,
    name,
    path::{PathKind, PathSegment},
    ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
    Function, HasSource, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution,
};
use ra_syntax::ast;

pub(crate) struct ExprValidator<'a, 'b: 'a> {
    func: Function,
    infer: Arc<InferenceResult>,
    sink: &'a mut DiagnosticSink<'b>,
}

impl<'a, 'b> ExprValidator<'a, 'b> {
    pub(crate) fn new(
        func: Function,
        infer: Arc<InferenceResult>,
        sink: &'a mut DiagnosticSink<'b>,
    ) -> ExprValidator<'a, 'b> {
        ExprValidator { func, infer, sink }
    }

    pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) {
        let body = self.func.body(db);

        for e in body.exprs() {
            if let (id, Expr::RecordLit { path, fields, spread }) = e {
                self.validate_record_literal(id, path, fields, *spread, db);
            }
        }

        let body_expr = &body[body.body_expr()];
        if let Expr::Block { statements: _, tail: Some(t) } = body_expr {
            self.validate_results_in_tail_expr(body.body_expr(), *t, db);
        }
    }

    fn validate_record_literal(
        &mut self,
        id: ExprId,
        _path: &Option<Path>,
        fields: &[RecordLitField],
        spread: Option<ExprId>,
        db: &impl HirDatabase,
    ) {
        if spread.is_some() {
            return;
        }

        let struct_def = match self.infer[id].as_adt() {
            Some((AdtDef::Struct(s), _)) => s,
            _ => return,
        };

        let lit_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
        let missed_fields: Vec<Name> = struct_def
            .fields(db)
            .iter()
            .filter_map(|f| {
                let name = f.name(db);
                if lit_fields.contains(&name) {
                    None
                } else {
                    Some(name)
                }
            })
            .collect();
        if missed_fields.is_empty() {
            return;
        }
        let source_map = self.func.body_source_map(db);
        let file_id = self.func.source(db).file_id;
        let parse = db.parse(file_id.original_file(db));
        let source_file = parse.tree();
        if let Some(field_list_node) = source_map
            .expr_syntax(id)
            .map(|ptr| ptr.to_node(source_file.syntax()))
            .and_then(RecordLit::cast)
            .and_then(|lit| lit.record_field_list())
        {
            let field_list_ptr = AstPtr::new(&field_list_node);
            self.sink.push(MissingFields {
                file: file_id,
                field_list: field_list_ptr,
                missed_fields,
            })
        }
    }

    fn validate_results_in_tail_expr(&mut self, body_id: ExprId, id: ExprId, db: &impl HirDatabase) {
        // the mismatch will be on the whole block currently
        let mismatch = match self.infer.type_mismatch_for_expr(body_id) {
            Some(m) => m,
            None => return,
        };

        let std_result_path = Path {
            kind: PathKind::Abs,
            segments: vec![
                PathSegment { name: name::STD, args_and_bindings: None },
                PathSegment { name: name::RESULT_MOD, args_and_bindings: None },
                PathSegment { name: name::RESULT_TYPE, args_and_bindings: None },
            ],
        };

        let resolver = self.func.resolver(db);
        let std_result_enum =
            match resolver.resolve_path_segments(db, &std_result_path).into_fully_resolved() {
                PerNs { types: Some(Resolution::Def(ModuleDef::Enum(e))), .. } => e,
                _ => return,
            };

        let std_result_ctor = TypeCtor::Adt(AdtDef::Enum(std_result_enum));
        let params = match &mismatch.expected {
            Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters,
            _ => return,
        };

        if params.len() == 2 && &params[0] == &mismatch.actual {
            let source_map = self.func.body_source_map(db);
            let file_id = self.func.source(db).file_id;

            if let Some(expr) = source_map.expr_syntax(id).and_then(|n| n.cast::<ast::Expr>()) {
                self.sink.push(MissingOkInTailExpr { file: file_id, expr });
            }
        }
    }
}
<|endoftext|>


<commit_before>//! See [RequestDispatcher].
use std::{fmt, panic, thread};

use lsp_server::ExtractError;
use serde::{de::DeserializeOwned, Serialize};

use crate::{
    global_state::{GlobalState, GlobalStateSnapshot},
    lsp_utils::is_cancelled,
    main_loop::Task,
    LspError, Result,
};

/// A visitor for routing a raw JSON request to an appropriate handler function.
///
/// Most requests are read-only and async and are handled on the threadpool
/// (`on` method).
///
/// Some read-only requests are latency sensitive, and are immediately handled
/// on the main loop thread (`on_sync`). These are typically typing-related
/// requests.
///
/// Some requests modify the state, and are run on the main thread to get
/// `&mut` (`on_sync_mut`).
///
/// Read-only requests are wrapped into `catch_unwind` -- they don't modify the
/// state, so it's OK to recover from their failures.
pub(crate) struct RequestDispatcher<'a> {
    pub(crate) req: Option<lsp_server::Request>,
    pub(crate) global_state: &'a mut GlobalState,
}

impl<'a> RequestDispatcher<'a> {
    /// Dispatches the request onto the current thread, given full access to
    /// mutable global state. Unlike all other methods here, this one isn't
    /// guarded by `catch_unwind`, so, please, don't make bugs :-)
    pub(crate) fn on_sync_mut<R>(
        &mut self,
        f: fn(&mut GlobalState, R::Params) -> Result<R::Result>,
    ) -> Result<&mut Self>
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug + 'static,
        R::Result: Serialize + 'static,
    {
        let (id, params, panic_context) = match self.parse::<R>() {
            Some(it) => it,
            None => return Ok(self),
        };
        let _pctx = stdx::panic_context::enter(panic_context);

        let result = f(self.global_state, params);
        let response = result_to_response::<R>(id, result);

        self.global_state.respond(response);
        Ok(self)
    }

    /// Dispatches the request onto the current thread.
    pub(crate) fn on_sync<R>(
        &mut self,
        f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
    ) -> Result<&mut Self>
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug + 'static,
        R::Result: Serialize + 'static,
    {
        let (id, params, panic_context) = match self.parse::<R>() {
            Some(it) => it,
            None => return Ok(self),
        };
        let global_state_snapshot = self.global_state.snapshot();

        let result = panic::catch_unwind(move || {
            let _pctx = stdx::panic_context::enter(panic_context);
            f(global_state_snapshot, params)
        });
        let response = thread_result_to_response::<R>(id, result);

        self.global_state.respond(response);
        Ok(self)
    }

    /// Dispatches the request onto thread pool
    pub(crate) fn on<R>(
        &mut self,
        f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
    ) -> &mut Self
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug + 'static,
        R::Result: Serialize + 'static,
    {
        let (id, params, panic_context) = match self.parse::<R>() {
            Some(it) => it,
            None => return self,
        };

        self.global_state.task_pool.handle.spawn({
            let world = self.global_state.snapshot();
            move || {
                let result = panic::catch_unwind(move || {
                    let _pctx = stdx::panic_context::enter(panic_context);
                    f(world, params)
                });
                let response = thread_result_to_response::<R>(id, result);
                Task::Response(response)
            }
        });

        self
    }

    pub(crate) fn finish(&mut self) {
        if let Some(req) = self.req.take() {
            tracing::error!("unknown request: {:?}", req);
            let response = lsp_server::Response::new_err(
                req.id,
                lsp_server::ErrorCode::MethodNotFound as i32,
                "unknown request".to_string(),
            );
            self.global_state.respond(response);
        }
    }

    fn parse<R>(&mut self) -> Option<(lsp_server::RequestId, R::Params, String)>
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + fmt::Debug + 'static,
    {
        let req = match &self.req {
            Some(req) if req.method == R::METHOD => self.req.take().unwrap(),
            _ => return None,
        };

        let res = crate::from_json(R::METHOD, req.params);
        match res {
            Ok(params) => {
                let panic_context =
                    format!("\nversion: {}\nrequest: {} {:#?}", env!("REV"), R::METHOD, params);
                Some((req.id, params, panic_context))
            }
            Err(err) => {
                let response = lsp_server::Response::new_err(
                    req.id,
                    lsp_server::ErrorCode::InvalidParams as i32,
                    err.to_string(),
                );
                self.global_state.respond(response);
                None
            }
        }
    }
}

fn thread_result_to_response<R>(
    id: lsp_server::RequestId,
    result: thread::Result<Result<R::Result>>,
) -> lsp_server::Response
where
    R: lsp_types::request::Request + 'static,
    R::Params: DeserializeOwned + 'static,
    R::Result: Serialize + 'static,
{
    match result {
        Ok(result) => result_to_response::<R>(id, result),
        Err(panic) => {
            let mut message = "server panicked".to_string();

            let panic_message = panic
                .downcast_ref::<String>()
                .map(String::as_str)
                .or_else(|| panic.downcast_ref::<&str>().copied());

            if let Some(panic_message) = panic_message {
                message.push_str(": ");
                message.push_str(panic_message)
            };

            lsp_server::Response::new_err(id, lsp_server::ErrorCode::InternalError as i32, message)
        }
    }
}

fn result_to_response<R>(
    id: lsp_server::RequestId,
    result: Result<R::Result>,
) -> lsp_server::Response
where
    R: lsp_types::request::Request + 'static,
    R::Params: DeserializeOwned + 'static,
    R::Result: Serialize + 'static,
{
    match result {
        Ok(resp) => lsp_server::Response::new_ok(id, &resp),
        Err(e) => match e.downcast::<LspError>() {
            Ok(lsp_error) => lsp_server::Response::new_err(id, lsp_error.code, lsp_error.message),
            Err(e) => {
                if is_cancelled(&*e) {
                    lsp_server::Response::new_err(
                        id,
                        lsp_server::ErrorCode::ContentModified as i32,
                        "content modified".to_string(),
                    )
                } else {
                    lsp_server::Response::new_err(
                        id,
                        lsp_server::ErrorCode::InternalError as i32,
                        e.to_string(),
                    )
                }
            }
        },
    }
}

pub(crate) struct NotificationDispatcher<'a> {
    pub(crate) not: Option<lsp_server::Notification>,
    pub(crate) global_state: &'a mut GlobalState,
}

impl<'a> NotificationDispatcher<'a> {
    pub(crate) fn on<N>(
        &mut self,
        f: fn(&mut GlobalState, N::Params) -> Result<()>,
    ) -> Result<&mut Self>
    where
        N: lsp_types::notification::Notification + 'static,
        N::Params: DeserializeOwned + Send + 'static,
    {
        let not = match self.not.take() {
            Some(it) => it,
            None => return Ok(self),
        };
        let params = match not.extract::<N::Params>(N::METHOD) {
            Ok(it) => it,
            Err(ExtractError::JsonError { method, error }) => {
                panic!("Invalid request\nMethod: {method}\n error: {error}",)
            }
            Err(ExtractError::MethodMismatch(not)) => {
                self.not = Some(not);
                return Ok(self);
            }
        };
        let _pctx = stdx::panic_context::enter(format!(
            "\nversion: {}\nnotification: {}",
            env!("REV"),
            N::METHOD
        ));
        f(self.global_state, params)?;
        Ok(self)
    }

    pub(crate) fn finish(&mut self) {
        if let Some(not) = &self.not {
            if !not.method.starts_with("$/") {
                tracing::error!("unhandled notification: {:?}", not);
            }
        }
    }
}
<commit_msg>minor: clarify error message<commit_after>//! See [RequestDispatcher].
use std::{fmt, panic, thread};

use lsp_server::ExtractError;
use serde::{de::DeserializeOwned, Serialize};

use crate::{
    global_state::{GlobalState, GlobalStateSnapshot},
    lsp_utils::is_cancelled,
    main_loop::Task,
    LspError, Result,
};

/// A visitor for routing a raw JSON request to an appropriate handler function.
///
/// Most requests are read-only and async and are handled on the threadpool
/// (`on` method).
///
/// Some read-only requests are latency sensitive, and are immediately handled
/// on the main loop thread (`on_sync`). These are typically typing-related
/// requests.
///
/// Some requests modify the state, and are run on the main thread to get
/// `&mut` (`on_sync_mut`).
///
/// Read-only requests are wrapped into `catch_unwind` -- they don't modify the
/// state, so it's OK to recover from their failures.
pub(crate) struct RequestDispatcher<'a> {
    pub(crate) req: Option<lsp_server::Request>,
    pub(crate) global_state: &'a mut GlobalState,
}

impl<'a> RequestDispatcher<'a> {
    /// Dispatches the request onto the current thread, given full access to
    /// mutable global state. Unlike all other methods here, this one isn't
    /// guarded by `catch_unwind`, so, please, don't make bugs :-)
    pub(crate) fn on_sync_mut<R>(
        &mut self,
        f: fn(&mut GlobalState, R::Params) -> Result<R::Result>,
    ) -> Result<&mut Self>
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug + 'static,
        R::Result: Serialize + 'static,
    {
        let (id, params, panic_context) = match self.parse::<R>() {
            Some(it) => it,
            None => return Ok(self),
        };
        let _pctx = stdx::panic_context::enter(panic_context);

        let result = f(self.global_state, params);
        let response = result_to_response::<R>(id, result);

        self.global_state.respond(response);
        Ok(self)
    }

    /// Dispatches the request onto the current thread.
    pub(crate) fn on_sync<R>(
        &mut self,
        f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
    ) -> Result<&mut Self>
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug + 'static,
        R::Result: Serialize + 'static,
    {
        let (id, params, panic_context) = match self.parse::<R>() {
            Some(it) => it,
            None => return Ok(self),
        };
        let global_state_snapshot = self.global_state.snapshot();

        let result = panic::catch_unwind(move || {
            let _pctx = stdx::panic_context::enter(panic_context);
            f(global_state_snapshot, params)
        });
        let response = thread_result_to_response::<R>(id, result);

        self.global_state.respond(response);
        Ok(self)
    }

    /// Dispatches the request onto thread pool
    pub(crate) fn on<R>(
        &mut self,
        f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
    ) -> &mut Self
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug + 'static,
        R::Result: Serialize + 'static,
    {
        let (id, params, panic_context) = match self.parse::<R>() {
            Some(it) => it,
            None => return self,
        };

        self.global_state.task_pool.handle.spawn({
            let world = self.global_state.snapshot();
            move || {
                let result = panic::catch_unwind(move || {
                    let _pctx = stdx::panic_context::enter(panic_context);
                    f(world, params)
                });
                let response = thread_result_to_response::<R>(id, result);
                Task::Response(response)
            }
        });

        self
    }

    pub(crate) fn finish(&mut self) {
        if let Some(req) = self.req.take() {
            tracing::error!("unknown request: {:?}", req);
            let response = lsp_server::Response::new_err(
                req.id,
                lsp_server::ErrorCode::MethodNotFound as i32,
                "unknown request".to_string(),
            );
            self.global_state.respond(response);
        }
    }

    fn parse<R>(&mut self) -> Option<(lsp_server::RequestId, R::Params, String)>
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + fmt::Debug + 'static,
    {
        let req = match &self.req {
            Some(req) if req.method == R::METHOD => self.req.take().unwrap(),
            _ => return None,
        };

        let res = crate::from_json(R::METHOD, req.params);
        match res {
            Ok(params) => {
                let panic_context =
                    format!("\nversion: {}\nrequest: {} {:#?}", env!("REV"), R::METHOD, params);
                Some((req.id, params, panic_context))
            }
            Err(err) => {
                let response = lsp_server::Response::new_err(
                    req.id,
                    lsp_server::ErrorCode::InvalidParams as i32,
                    err.to_string(),
                );
                self.global_state.respond(response);
                None
            }
        }
    }
}

fn thread_result_to_response<R>(
    id: lsp_server::RequestId,
    result: thread::Result<Result<R::Result>>,
) -> lsp_server::Response
where
    R: lsp_types::request::Request + 'static,
    R::Params: DeserializeOwned + 'static,
    R::Result: Serialize + 'static,
{
    match result {
        Ok(result) => result_to_response::<R>(id, result),
        Err(panic) => {
            let mut message = "request handler panicked".to_string();

            let panic_message = panic
                .downcast_ref::<String>()
                .map(String::as_str)
                .or_else(|| panic.downcast_ref::<&str>().copied());

            if let Some(panic_message) = panic_message {
                message.push_str(": ");
                message.push_str(panic_message)
            };

            lsp_server::Response::new_err(id, lsp_server::ErrorCode::InternalError as i32, message)
        }
    }
}

fn result_to_response<R>(
    id: lsp_server::RequestId,
    result: Result<R::Result>,
) -> lsp_server::Response
where
    R: lsp_types::request::Request + 'static,
    R::Params: DeserializeOwned + 'static,
    R::Result: Serialize + 'static,
{
    match result {
        Ok(resp) => lsp_server::Response::new_ok(id, &resp),
        Err(e) => match e.downcast::<LspError>() {
            Ok(lsp_error) => lsp_server::Response::new_err(id, lsp_error.code, lsp_error.message),
            Err(e) => {
                if is_cancelled(&*e) {
                    lsp_server::Response::new_err(
                        id,
                        lsp_server::ErrorCode::ContentModified as i32,
                        "content modified".to_string(),
                    )
                } else {
                    lsp_server::Response::new_err(
                        id,
                        lsp_server::ErrorCode::InternalError as i32,
                        e.to_string(),
                    )
                }
            }
        },
    }
}

pub(crate) struct NotificationDispatcher<'a> {
    pub(crate) not: Option<lsp_server::Notification>,
    pub(crate) global_state: &'a mut GlobalState,
}

impl<'a> NotificationDispatcher<'a> {
    pub(crate) fn on<N>(
        &mut self,
        f: fn(&mut GlobalState, N::Params) -> Result<()>,
    ) -> Result<&mut Self>
    where
        N: lsp_types::notification::Notification + 'static,
        N::Params: DeserializeOwned + Send + 'static,
    {
        let not = match self.not.take() {
            Some(it) => it,
            None => return Ok(self),
        };
        let params = match not.extract::<N::Params>(N::METHOD) {
            Ok(it) => it,
            Err(ExtractError::JsonError { method, error }) => {
                panic!("Invalid request\nMethod: {method}\n error: {error}",)
            }
            Err(ExtractError::MethodMismatch(not)) => {
                self.not = Some(not);
                return Ok(self);
            }
        };
        let _pctx = stdx::panic_context::enter(format!(
            "\nversion: {}\nnotification: {}",
            env!("REV"),
            N::METHOD
        ));
        f(self.global_state, params)?;
        Ok(self)
    }

    pub(crate) fn finish(&mut self) {
        if let Some(not) = &self.not {
            if !not.method.starts_with("$/") {
                tracing::error!("unhandled notification: {:?}", not);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::{
    sync::{
        atomic::{AtomicBool, Ordering},
        mpsc, Arc,
    },
    thread,
};

use super::MouseState;
use crate::{
    event::{ButtonState, Key, KeyEvent, MouseButton, MouseEvent},
    render::RenderContext2D,
    window_adapter::WindowAdapter,
    WindowRequest,
};

#[cfg(not(target_os = "redox"))]
use sdl2::event;

use orbclient::Renderer;
use raw_window_handle::HasRawWindowHandle;

use orbtk_utils::Point;

/// Represents a wrapper for a orbclient window. It handles events, propagate them to
/// the window adapter and handles the update and render pipeline.
pub struct Window
where
    A: WindowAdapter,
{
    window: orbclient::Window,
    adapter: A,
    render_context: RenderContext2D,
    request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    //window_state: WindowState,
    mouse: MouseState,
    update: bool,
    redraw: Arc<AtomicBool>,
    close: bool,
    has_clipboard_update: bool,
    #[cfg(not(target_os = "redox"))]
    _sdl2_sync_thread: Option<thread::JoinHandle<()>>,
}

// internal method to sync if OrbClient backend is sdl2
#[cfg(not(target_os = "redox"))]
fn init_sync(
    window: &orbclient::Window,
    receiver: mpsc::Receiver<WindowRequest>,
    redraw: Arc<AtomicBool>,
) -> (mpsc::Receiver<WindowRequest>, thread::JoinHandle<()>) {
    let (internal_sender, internal_receiver) = mpsc::channel();

    let event_sender = window.event_sender();

    // prevent multiple redraw a the same time
    let mut should_redraw = false;

    let _sdl2_sync_thread = thread::spawn(move || loop {
        for request in receiver.try_iter() {
            let _ = internal_sender.send(request.clone());
            if request == WindowRequest::Redraw && !should_redraw && !redraw.load(Ordering::Relaxed)
            {
                let _ = event_sender.push_event(event::Event::Window {
                    window_id: 0,
                    timestamp: 0,
                    win_event: event::WindowEvent::None,
                });

                should_redraw = true;
            }
        }

        should_redraw = false;
    });

    (internal_receiver, _sdl2_sync_thread)
}

impl Window
where
    A: WindowAdapter,
{
    #[cfg(target_os = "redox")]
    pub fn new(
        window: orbclient::Window,
        adapter: A,
        render_context: RenderContext2D,
        request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    ) -> Self {
        Window {
            window,
            adapter,
            render_context,
            request_receiver,
            // window_state: WindowState::default(),
            mouse: MouseState::default(),
            update: true,
            redraw: true,
            close: false,
            has_clipboard_update: true,
        }
    }

    #[cfg(not(target_os = "redox"))]
    pub fn new(
        window: orbclient::Window,
        adapter: A,
        render_context: RenderContext2D,
        request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    ) -> Self {
        let mut adapter = adapter;
        let redraw: Arc<AtomicBool> = Arc::new(AtomicBool::new(true));

        adapter.set_raw_window_handle(window.raw_window_handle());

        let (request_receiver, _sdl2_sync_thread) = {
            if let Some(receiver) = request_receiver {
                let (rec, sync) = init_sync(&window, receiver, redraw.clone());
                (Some(rec), Some(sync))
            } else {
                (None, None)
            }
        };

        Window {
            window,
            adapter,
            render_context,
            _sdl2_sync_thread,
            request_receiver,
            // window_state: WindowState::default(),
            mouse: MouseState::default(),
            update: true,
            redraw,
            close: false,
            has_clipboard_update: true,
        }
    }

    #[cfg(not(target_os = "redox"))]
    fn has_clipboard_update(&self) -> bool {
        self.has_clipboard_update
    }

    // todo: workaround until clipboard update events available on orbital
    #[cfg(target_os = "redox")]
    fn has_clipboard_update(&self) -> bool {
        true
    }
}

#[cfg(not(target_os = "redox"))]
unsafe impl raw_window_handle::HasRawWindowHandle for Window
where
    A: WindowAdapter,
{
    fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
        self.window.raw_window_handle()
    }
}

impl Window
where
    A: WindowAdapter,
{
    /// Check if the window is open.
    pub fn is_open(&self) -> bool {
        !self.close
    }

    fn push_mouse_event(&mut self, pressed: bool, button: MouseButton) {
        let state = if pressed {
            ButtonState::Down
        } else {
            ButtonState::Up
        };

        self.adapter.mouse_event(MouseEvent {
            position: Point::new(self.mouse.mouse_pos.0 as f64, self.mouse.mouse_pos.1 as f64),
            button,
            state,
        });
    }

    fn push_key_event(&mut self, key_event: orbclient::KeyEvent) {
        let mut key = Key::from(key_event.character);
        let state = {
            if key_event.pressed {
                ButtonState::Down
            } else {
                ButtonState::Up
            }
        };

        let text = {
            if key_event.character != '\0'
                && key_event.character != '\n'
                && key_event.character != '\u{1b}'
            {
                key_event.character.to_string()
            } else {
                match key_event.scancode {
                    orbclient::K_BKSP => key = Key::Backspace,
                    orbclient::K_LEFT => key = Key::Left,
                    orbclient::K_RIGHT => key = Key::Right,
                    orbclient::K_UP => key = Key::Up,
                    orbclient::K_DOWN => key = Key::Down,
                    orbclient::K_DEL => key = Key::Delete,
                    orbclient::K_ENTER => key = Key::Enter,
                    orbclient::K_CTRL => key = Key::Control,
                    orbclient::K_LEFT_SHIFT => key = Key::ShiftL,
                    orbclient::K_RIGHT_SHIFT => key = Key::ShiftR,
                    orbclient::K_ALT => key = Key::Alt,
                    orbclient::K_ESC => key = Key::Escape,
                    orbclient::K_CAPS => key = Key::CapsLock,
                    orbclient::K_HOME => {
                        key = Key::Home;
                    }
                    _ => key = Key::Unknown,
                };
                String::default()
            }
        };

        self.adapter.key_event(KeyEvent { key, text, state });
    }

    /// Updates the clipboard.
    pub fn update_clipboard(&mut self) {
        let mut clipboard_value = if self.has_clipboard_update() {
            self.has_clipboard_update = false;
            Some(self.window.clipboard())
        } else {
            None
        };

        self.adapter.clipboard_update(&mut clipboard_value);

        if let Some(value) = clipboard_value {
            self.window.set_clipboard(value.as_str());
        }
    }

    /// Drain events and propagate the events to the adapter.
    pub fn drain_events(&mut self) {
        for event in self.window.events() {
            match event.to_option() {
                orbclient::EventOption::Key(event) => {
                    self.push_key_event(event);
                    self.update = true;
                }
                orbclient::EventOption::Mouse(event) => {
                    self.mouse.mouse_pos = (event.x as f32, event.y as f32);
                    self.adapter.mouse(event.x as f64, event.y as f64);
                    self.update = true;
                }
                orbclient::EventOption::MouseRelative(_) => {}
                orbclient::EventOption::ClipboardUpdate(_) => {
                    self.has_clipboard_update = true;
                }
                orbclient::EventOption::Button(event) => {
                    if event.left != self.mouse.button_left {
                        if event.left {
                            self.push_mouse_event(true, MouseButton::Left);
                        } else {
                            self.push_mouse_event(false, MouseButton::Left);
                        }
                        self.mouse.button_left = event.left;
                        self.update = true;
                    }

                    if event.middle != self.mouse.button_middle {
                        if event.middle {
                            self.push_mouse_event(true, MouseButton::Middle);
                        } else {
                            self.push_mouse_event(false, MouseButton::Middle);
                        }
                        self.mouse.button_middle = event.middle;
                        self.update = true;
                    }

                    if event.right != self.mouse.button_right {
                        if event.right {
                            self.push_mouse_event(true, MouseButton::Right);
                        } else {
                            self.push_mouse_event(false, MouseButton::Right);
                        }
                        self.mouse.button_right = event.right;
                        self.update = true;
                    }
                }
                orbclient::EventOption::Scroll(event) => {
                    self.adapter.scroll(event.x as f64, event.y as f64);
                    self.update = true;
                }
                orbclient::EventOption::Quit(_) => {
                    self.close = true;
                    self.update = true
                }
                orbclient::EventOption::Focus(_) => {}
                orbclient::EventOption::Move(_) => {}
                orbclient::EventOption::Resize(event) => {
                    self.adapter.resize(event.width as f64, event.height as f64);
                    self.render_context
                        .resize(event.width as f64, event.height as f64);
                    self.update = true;
                    self.redraw.store(true, Ordering::Relaxed);
                }
                orbclient::EventOption::Screen(_) => {}
                orbclient::EventOption::Clipboard(_) => {}
                orbclient::EventOption::Drop(event) => {
                    self.window.sync_path();
                    if let Some(text) = self.window.pop_drop_content() {
                        if event.kind == orbclient::DROP_FILE {
                            self.adapter.file_drop_event(text);
                        } else {
                            self.adapter.text_drop_event(text);
                        }
                    }
                }
                orbclient::EventOption::Unknown(_) => println!("unkown"),
                orbclient::EventOption::None => println!("None"),
            }
        }
    }

    /// Receives window request from the application and handles them.
    pub fn receive_requests(&mut self) {
        if let Some(request_receiver) = &self.request_receiver {
            for request in request_receiver.try_iter() {
                match request {
                    WindowRequest::Redraw => {
                        if !self.update && !self.redraw.load(Ordering::Relaxed) {
                            self.update = true;
                            self.redraw.store(true, Ordering::Relaxed)
                        }
                    }
                    WindowRequest::ChangeTitle(title) => {
                        self.window.set_title(title.as_str());
                        self.update = true;
                        self.redraw.store(true, Ordering::Relaxed)
                    }
                    WindowRequest::Close => {
                        self.close = true;
                    }
                }
            }
        }
    }

    /// Runs update on the adapter.
    pub fn update(&mut self) {
        //super::CONSOLE.time("complete");
        if !self.update {
            return;
        }
        self.adapter.run(&mut self.render_context);
        self.update = false;
        self.redraw.store(true, Ordering::Relaxed)
    }

    /// Swaps the current frame buffer.
    pub fn render(&mut self) {
        if self.redraw.load(Ordering::Relaxed) {
            let color_data: Vec<orbclient::Color> = self
                .render_context
                .data()
                .iter()
                .map(|v| orbclient::Color { data: *v })
                .collect();

            if color_data.len() == self.window.data().len() {
                self.window
                    .data_mut()
                    .clone_from_slice(color_data.as_slice());

                // CONSOLE.time_end("render");
                self.redraw.store(false, Ordering::Relaxed)
                //super::CONSOLE.time_end("complete");
            }
        }

        self.window.sync();
    }
}
<commit_msg>fix redox build<commit_after>use std::sync::{
    atomic::{AtomicBool, Ordering},
    mpsc, Arc,
};

#[cfg(not(target_os = "redox"))]
use std::thread;

use super::MouseState;
use crate::{
    event::{ButtonState, Key, KeyEvent, MouseButton, MouseEvent},
    render::RenderContext2D,
    window_adapter::WindowAdapter,
    WindowRequest,
};

#[cfg(not(target_os = "redox"))]
use sdl2::event;

use orbclient::Renderer;

#[cfg(not(target_os = "redox"))]
use raw_window_handle::HasRawWindowHandle;

use orbtk_utils::Point;

/// Represents a wrapper for a orbclient window. It handles events, propagate them to
/// the window adapter and handles the update and render pipeline.
pub struct Window
where
    A: WindowAdapter,
{
    window: orbclient::Window,
    adapter: A,
    render_context: RenderContext2D,
    request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    //window_state: WindowState,
    mouse: MouseState,
    update: bool,
    redraw: Arc<AtomicBool>,
    close: bool,
    has_clipboard_update: bool,
    #[cfg(not(target_os = "redox"))]
    _sdl2_sync_thread: Option<thread::JoinHandle<()>>,
}

// internal method to sync if OrbClient backend is sdl2
#[cfg(not(target_os = "redox"))]
fn init_sync(
    window: &orbclient::Window,
    receiver: mpsc::Receiver<WindowRequest>,
    redraw: Arc<AtomicBool>,
) -> (mpsc::Receiver<WindowRequest>, thread::JoinHandle<()>) {
    let (internal_sender, internal_receiver) = mpsc::channel();

    let event_sender = window.event_sender();

    // prevent multiple redraw a the same time
    let mut should_redraw = false;

    let _sdl2_sync_thread = thread::spawn(move || loop {
        for request in receiver.try_iter() {
            let _ = internal_sender.send(request.clone());
            if request == WindowRequest::Redraw && !should_redraw && !redraw.load(Ordering::Relaxed)
            {
                let _ = event_sender.push_event(event::Event::Window {
                    window_id: 0,
                    timestamp: 0,
                    win_event: event::WindowEvent::None,
                });

                should_redraw = true;
            }
        }

        should_redraw = false;
    });

    (internal_receiver, _sdl2_sync_thread)
}

impl Window
where
    A: WindowAdapter,
{
    #[cfg(target_os = "redox")]
    pub fn new(
        window: orbclient::Window,
        adapter: A,
        render_context: RenderContext2D,
        request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    ) -> Self {
        Window {
            window,
            adapter,
            render_context,
            request_receiver,
            // window_state: WindowState::default(),
            mouse: MouseState::default(),
            update: true,
            redraw: AtomicBool::new(true),
            close: false,
            has_clipboard_update: true,
        }
    }

    #[cfg(not(target_os = "redox"))]
    pub fn new(
        window: orbclient::Window,
        adapter: A,
        render_context: RenderContext2D,
        request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    ) -> Self {
        let mut adapter = adapter;
        let redraw: Arc<AtomicBool> = Arc::new(AtomicBool::new(true));

        adapter.set_raw_window_handle(window.raw_window_handle());

        let (request_receiver, _sdl2_sync_thread) = {
            if let Some(receiver) = request_receiver {
                let (rec, sync) = init_sync(&window, receiver, redraw.clone());
                (Some(rec), Some(sync))
            } else {
                (None, None)
            }
        };

        Window {
            window,
            adapter,
            render_context,
            _sdl2_sync_thread,
            request_receiver,
            // window_state: WindowState::default(),
            mouse: MouseState::default(),
            update: true,
            redraw,
            close: false,
            has_clipboard_update: true,
        }
    }

    #[cfg(not(target_os = "redox"))]
    fn has_clipboard_update(&self) -> bool {
        self.has_clipboard_update
    }

    // todo: workaround until clipboard update events available on orbital
    #[cfg(target_os = "redox")]
    fn has_clipboard_update(&self) -> bool {
        true
    }
}

#[cfg(not(target_os = "redox"))]
unsafe impl raw_window_handle::HasRawWindowHandle for Window
where
    A: WindowAdapter,
{
    fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
        self.window.raw_window_handle()
    }
}

impl Window
where
    A: WindowAdapter,
{
    /// Check if the window is open.
    pub fn is_open(&self) -> bool {
        !self.close
    }

    fn push_mouse_event(&mut self, pressed: bool, button: MouseButton) {
        let state = if pressed {
            ButtonState::Down
        } else {
            ButtonState::Up
        };

        self.adapter.mouse_event(MouseEvent {
            position: Point::new(self.mouse.mouse_pos.0 as f64, self.mouse.mouse_pos.1 as f64),
            button,
            state,
        });
    }

    fn push_key_event(&mut self, key_event: orbclient::KeyEvent) {
        let mut key = Key::from(key_event.character);
        let state = {
            if key_event.pressed {
                ButtonState::Down
            } else {
                ButtonState::Up
            }
        };

        let text = {
            if key_event.character != '\0'
                && key_event.character != '\n'
                && key_event.character != '\u{1b}'
            {
                key_event.character.to_string()
            } else {
                match key_event.scancode {
                    orbclient::K_BKSP => key = Key::Backspace,
                    orbclient::K_LEFT => key = Key::Left,
                    orbclient::K_RIGHT => key = Key::Right,
                    orbclient::K_UP => key = Key::Up,
                    orbclient::K_DOWN => key = Key::Down,
                    orbclient::K_DEL => key = Key::Delete,
                    orbclient::K_ENTER => key = Key::Enter,
                    orbclient::K_CTRL => key = Key::Control,
                    orbclient::K_LEFT_SHIFT => key = Key::ShiftL,
                    orbclient::K_RIGHT_SHIFT => key = Key::ShiftR,
                    orbclient::K_ALT => key = Key::Alt,
                    orbclient::K_ESC => key = Key::Escape,
                    orbclient::K_CAPS => key = Key::CapsLock,
                    orbclient::K_HOME => {
                        key = Key::Home;
                    }
                    _ => key = Key::Unknown,
                };
                String::default()
            }
        };

        self.adapter.key_event(KeyEvent { key, text, state });
    }

    /// Updates the clipboard.
    pub fn update_clipboard(&mut self) {
        let mut clipboard_value = if self.has_clipboard_update() {
            self.has_clipboard_update = false;
            Some(self.window.clipboard())
        } else {
            None
        };

        self.adapter.clipboard_update(&mut clipboard_value);

        if let Some(value) = clipboard_value {
            self.window.set_clipboard(value.as_str());
        }
    }

    /// Drain events and propagate the events to the adapter.
    pub fn drain_events(&mut self) {
        for event in self.window.events() {
            match event.to_option() {
                orbclient::EventOption::Key(event) => {
                    self.push_key_event(event);
                    self.update = true;
                }
                orbclient::EventOption::Mouse(event) => {
                    self.mouse.mouse_pos = (event.x as f32, event.y as f32);
                    self.adapter.mouse(event.x as f64, event.y as f64);
                    self.update = true;
                }
                orbclient::EventOption::MouseRelative(_) => {}
                orbclient::EventOption::ClipboardUpdate(_) => {
                    self.has_clipboard_update = true;
                }
                orbclient::EventOption::Button(event) => {
                    if event.left != self.mouse.button_left {
                        if event.left {
                            self.push_mouse_event(true, MouseButton::Left);
                        } else {
                            self.push_mouse_event(false, MouseButton::Left);
                        }
                        self.mouse.button_left = event.left;
                        self.update = true;
                    }

                    if event.middle != self.mouse.button_middle {
                        if event.middle {
                            self.push_mouse_event(true, MouseButton::Middle);
                        } else {
                            self.push_mouse_event(false, MouseButton::Middle);
                        }
                        self.mouse.button_middle = event.middle;
                        self.update = true;
                    }

                    if event.right != self.mouse.button_right {
                        if event.right {
                            self.push_mouse_event(true, MouseButton::Right);
                        } else {
                            self.push_mouse_event(false, MouseButton::Right);
                        }
                        self.mouse.button_right = event.right;
                        self.update = true;
                    }
                }
                orbclient::EventOption::Scroll(event) => {
                    self.adapter.scroll(event.x as f64, event.y as f64);
                    self.update = true;
                }
                orbclient::EventOption::Quit(_) => {
                    self.close = true;
                    self.update = true
                }
                orbclient::EventOption::Focus(_) => {}
                orbclient::EventOption::Move(_) => {}
                orbclient::EventOption::Resize(event) => {
                    self.adapter.resize(event.width as f64, event.height as f64);
                    self.render_context
                        .resize(event.width as f64, event.height as f64);
                    self.update = true;
                    self.redraw.store(true, Ordering::Relaxed);
                }
                orbclient::EventOption::Screen(_) => {}
                orbclient::EventOption::Clipboard(_) => {}
                orbclient::EventOption::Drop(event) => {
                    self.window.sync_path();
                    if let Some(text) = self.window.pop_drop_content() {
                        if event.kind == orbclient::DROP_FILE {
                            self.adapter.file_drop_event(text);
                        } else {
                            self.adapter.text_drop_event(text);
                        }
                    }
                }
                orbclient::EventOption::Unknown(_) => println!("unkown"),
                orbclient::EventOption::None => println!("None"),
            }
        }
    }

    /// Receives window request from the application and handles them.
    pub fn receive_requests(&mut self) {
        if let Some(request_receiver) = &self.request_receiver {
            for request in request_receiver.try_iter() {
                match request {
                    WindowRequest::Redraw => {
                        if !self.update && !self.redraw.load(Ordering::Relaxed) {
                            self.update = true;
                            self.redraw.store(true, Ordering::Relaxed)
                        }
                    }
                    WindowRequest::ChangeTitle(title) => {
                        self.window.set_title(title.as_str());
                        self.update = true;
                        self.redraw.store(true, Ordering::Relaxed)
                    }
                    WindowRequest::Close => {
                        self.close = true;
                    }
                }
            }
        }
    }

    /// Runs update on the adapter.
    pub fn update(&mut self) {
        //super::CONSOLE.time("complete");
        if !self.update {
            return;
        }
        self.adapter.run(&mut self.render_context);
        self.update = false;
        self.redraw.store(true, Ordering::Relaxed)
    }

    /// Swaps the current frame buffer.
    pub fn render(&mut self) {
        if self.redraw.load(Ordering::Relaxed) {
            let color_data: Vec<orbclient::Color> = self
                .render_context
                .data()
                .iter()
                .map(|v| orbclient::Color { data: *v })
                .collect();

            if color_data.len() == self.window.data().len() {
                self.window
                    .data_mut()
                    .clone_from_slice(color_data.as_slice());

                // CONSOLE.time_end("render");
                self.redraw.store(false, Ordering::Relaxed)
                //super::CONSOLE.time_end("complete");
            }
        }

        self.window.sync();
    }
}
<|endoftext|>


<commit_before>use libc::{uint64_t, int64_t, c_void, c_char, c_double};
use std::ffi::CString;
use std::ptr;
use energymon_sys::energymon::EnergyMon;

#[link(name = "hbt-acc-pow")]
extern {
    fn heartbeat_acc_pow_init(parent: *mut c_void,
                              window_size: uint64_t,
                              buffer_depth: uint64_t,
                              log_name: *const c_char,
                              num_energy_impls: uint64_t,
                              energy_impls: *mut EnergyMon) -> *mut c_void;

    fn heartbeat_acc(hb: *mut c_void,
                     user_tag: uint64_t,
                     work: uint64_t,
                     accuracy: c_double,
                     hb_prev: *mut c_void) -> int64_t;

    fn heartbeat_finish(hb: *mut c_void);

    fn hb_get_user_tag(hb: *const c_void) -> uint64_t;

    fn hb_get_window_rate(hb: *const c_void) -> c_double;

    fn hb_get_window_power(hb: *const c_void) -> c_double;
}

/// A `Heartbeat` is used for tracking performance/accuracy/power of recurring jobs.
pub struct Heartbeat {
    /// The underlying C struct `heartbeat_t`.
    pub hb: *mut c_void,
}

impl Heartbeat {
    /// Allocate and initialize a new `Heartbeat` with its underlying C struct.
    pub fn new(parent: Option<&mut Heartbeat>,
               window_size: u64,
               buffer_depth: u64,
               log_name: Option<&str>,
               energy_impl: Option<&mut EnergyMon>) -> Result<Heartbeat, String> {
        let parent = match parent {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        let log_name = match log_name {
          Some(n) => CString::new(n).unwrap().as_ptr(),
          None => ptr::null(),
        };
        let num_energy_impls: u64;
        let mut em: *mut EnergyMon;
        if energy_impl.is_some() {
            num_energy_impls = 1;
            em = energy_impl.unwrap();
        } else {
            num_energy_impls = 0;
            em = ptr::null_mut();
        }
        let heart = unsafe {
            heartbeat_acc_pow_init(parent, window_size, buffer_depth, log_name,
                                   num_energy_impls, em)
        };
        if heart.is_null() {
            return Err("Failed to initialize heartbeat".to_string());
        }
        Ok(Heartbeat { hb: heart, })
    }

    /// Issue a heartbeat.
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     accuracy: f64,
                     hb_prev: Option<&Heartbeat>) -> i64 {
        let hb_prev = match hb_prev {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        unsafe {
            heartbeat_acc(self.hb, tag, work, accuracy, hb_prev)
        }
    }

    /// Utility function to get the most recent user-specified tag
    pub fn get_tag(&mut self) -> u64 {
        unsafe {
            hb_get_user_tag(self.hb)
        }
    }

    /// Utility function to get the current window performance.
    pub fn get_window_perf(&mut self) -> f64 {
        unsafe {
            hb_get_window_rate(self.hb)
        }
    }

    /// Utility function to get the current window power.
    pub fn get_window_pwr(&mut self) -> f64 {
        unsafe {
            hb_get_window_power(self.hb)
        }
    }
}

impl Drop for Heartbeat {
    /// Cleans up and deallocates the underlying C struct.
    fn drop(&mut self) {
        unsafe {
            heartbeat_finish(self.hb);
        }
    }
}

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

    #[test]
    fn test_no_energymon() {
        let mut hb = Heartbeat::new(None, 20, 20, None, None).unwrap();
        hb.heartbeat(0, 1, 0.0, None);
    }
}
<commit_msg>Change Err to return static str ref instead of String<commit_after>use libc::{uint64_t, int64_t, c_void, c_char, c_double};
use std::ffi::CString;
use std::ptr;
use energymon_sys::energymon::EnergyMon;

#[link(name = "hbt-acc-pow")]
extern {
    fn heartbeat_acc_pow_init(parent: *mut c_void,
                              window_size: uint64_t,
                              buffer_depth: uint64_t,
                              log_name: *const c_char,
                              num_energy_impls: uint64_t,
                              energy_impls: *mut EnergyMon) -> *mut c_void;

    fn heartbeat_acc(hb: *mut c_void,
                     user_tag: uint64_t,
                     work: uint64_t,
                     accuracy: c_double,
                     hb_prev: *mut c_void) -> int64_t;

    fn heartbeat_finish(hb: *mut c_void);

    fn hb_get_user_tag(hb: *const c_void) -> uint64_t;

    fn hb_get_window_rate(hb: *const c_void) -> c_double;

    fn hb_get_window_power(hb: *const c_void) -> c_double;
}

/// A `Heartbeat` is used for tracking performance/accuracy/power of recurring jobs.
pub struct Heartbeat {
    /// The underlying C struct `heartbeat_t`.
    pub hb: *mut c_void,
}

impl Heartbeat {
    /// Allocate and initialize a new `Heartbeat` with its underlying C struct.
    pub fn new(parent: Option<&mut Heartbeat>,
               window_size: u64,
               buffer_depth: u64,
               log_name: Option<&str>,
               energy_impl: Option<&mut EnergyMon>) -> Result<Heartbeat, &'static str> {
        let parent = match parent {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        let log_name = match log_name {
          Some(n) => CString::new(n).unwrap().as_ptr(),
          None => ptr::null(),
        };
        let num_energy_impls: u64;
        let mut em: *mut EnergyMon;
        if energy_impl.is_some() {
            num_energy_impls = 1;
            em = energy_impl.unwrap();
        } else {
            num_energy_impls = 0;
            em = ptr::null_mut();
        }
        let heart = unsafe {
            heartbeat_acc_pow_init(parent, window_size, buffer_depth, log_name,
                                   num_energy_impls, em)
        };
        if heart.is_null() {
            return Err("Failed to initialize heartbeat");
        }
        Ok(Heartbeat { hb: heart, })
    }

    /// Issue a heartbeat.
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     accuracy: f64,
                     hb_prev: Option<&Heartbeat>) -> i64 {
        let hb_prev = match hb_prev {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        unsafe {
            heartbeat_acc(self.hb, tag, work, accuracy, hb_prev)
        }
    }

    /// Utility function to get the most recent user-specified tag
    pub fn get_tag(&mut self) -> u64 {
        unsafe {
            hb_get_user_tag(self.hb)
        }
    }

    /// Utility function to get the current window performance.
    pub fn get_window_perf(&mut self) -> f64 {
        unsafe {
            hb_get_window_rate(self.hb)
        }
    }

    /// Utility function to get the current window power.
    pub fn get_window_pwr(&mut self) -> f64 {
        unsafe {
            hb_get_window_power(self.hb)
        }
    }
}

impl Drop for Heartbeat {
    /// Cleans up and deallocates the underlying C struct.
    fn drop(&mut self) {
        unsafe {
            heartbeat_finish(self.hb);
        }
    }
}

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

    #[test]
    fn test_no_energymon() {
        let mut hb = Heartbeat::new(None, 20, 20, None, None).unwrap();
        hb.heartbeat(0, 1, 0.0, None);
    }
}
<|endoftext|>


<commit_before>/* hil::timer -- Traits and structures for software timers.
 *
 * Support for virtualized software timers on top of a single hardware
 * alarm (counter interrupt). Currently traits do not specify the time
 * units of the timers; a future version will.
 *
 * The four relevant types are:
 *   - Timer: the trait that provides virtualized timers
 *   - TimerMux: the struct that implements Timer on top of Alarm
 *   - TimerRequest: the structure a caller must pass in when requesting
 *                   a timer
 *   - TimerCB: the trait which has the callback for when the timer fires
 *
 * The TimerRequest structure contains a reference to a TimerCB. So
 * to invoke a timer, an application defines a structure that implements
 * TimerCB, creates a TimerRequest whose callback field is the TimerCB
 * (either through new() or initialization), then passes TimerRequest to
 * calls to Timer.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Author: Amit Levy <levya@cs.stanford.edu>
 * Date: 7/16/15
 */
#![allow(dead_code)]

use core::prelude::*;
use core::mem::transmute;
use alarm;

// If a timer is late (was supposed to fire in the past), LATE_DELAY
// specifies how far in the future to fire it. This number needs to be
// > 1 in case the counter ticks between reading it and setting the
// overflow value. Set it to 5 just to be safe.
const LATE_DELAY: u32 = 5;

pub trait TimerCB {
    fn fired(&mut self, &'static mut TimerRequest, now: u32);
}

pub trait Timer {
    fn now(&self) -> u32;
    fn cancel(&mut self, &'static mut TimerRequest);
    fn oneshot(&mut self, interval: u32, &'static mut TimerRequest);
    fn repeat(&mut self, interval: u32, &'static mut TimerRequest);
}

pub struct TimerRequest {
    pub next: Option<&'static mut TimerRequest>,
    pub is_active: bool,
    pub is_repeat: bool,
    pub when: u32,
    pub interval: u32,
    pub callback: Option<&'static mut TimerCB>
}

impl TimerRequest {
    pub fn new(cb: &'static mut TimerCB) -> TimerRequest {
        TimerRequest {
            next:      None,
            is_active: false,
            is_repeat: false,
            when:      0,
            interval:  0,
            callback:  Some(cb)
        }
    }
}

pub struct VirtualTimer {
    request: *mut TimerRequest,
    internal: &'static mut Timer
}

impl VirtualTimer {
    pub fn new(timer: &'static mut Timer, req: &'static mut TimerRequest)
        -> VirtualTimer {
        VirtualTimer { request: req, internal: timer }
    }

    pub fn repeat(&mut self, interval: u32) {
        unsafe {
            self.internal.repeat(interval, transmute(self.request))
        }
    }

    pub fn oneshot(&mut self, interval: u32) {
        unsafe {
            self.internal.oneshot(interval, transmute(self.request))
        }
    }

    pub fn cancel(&mut self) {
        unsafe {
            self.internal.cancel(transmute(self.request))
        }
    }

    pub fn now(&self) -> u32 {
        self.internal.now()
    }
}

pub struct TimerMux {
    request: Option<&'static mut TimerRequest>,
    internal: &'static mut alarm::Alarm
}

impl TimerMux {
    pub fn new(internal: &'static mut alarm::Alarm) -> TimerMux {
        TimerMux {
            request: None,
            internal: internal
        }
    }

    /*
     * There are two pairs of functions for manipulating the ordered
     * linked list of outstanding timers
     *
     *  insert/delete: operate on list, inserting or deleting an entry
     *  add/remove: operate on list, and reconfigure underlying hardware
     *              alarm if first element of list changes
     *
     * add/remove are wrappers around insert/delete.
     */

    /* Insert a TimerRequest into the linked list, reconfiguring the
     * hardware alarm if it is inserted as the first element. */
    fn add(&mut self, request: &'static mut TimerRequest) -> bool {
        let changed = self.insert(request);
        if changed {
            self.start_request();
        }
        changed
    }

    /* Remove a TimerRequest into the linked list, reconfiguring the
     * hardware alarm if it was the first element. */
    fn remove(&mut self, request: &'static mut TimerRequest) -> bool {
        let changed = self.delete(request);
        if changed {
            self.start_request();
        }
        changed
    }

    /* Insert a TimerRequest into the linked list. Returns whether hardware
    * clock has to be recalculated (inserted timer is now first timer) */
    fn insert(&mut self, request: &'static mut TimerRequest) -> bool {
        if request.next.is_some() { // Already on a list, this is an error!
            false
        } else if self.request.is_none() {
            self.request = Some(request);
            true
        } else {
            let mut first = true;
            let mut done = false;
            let mut copt = &mut self.request;
            while !done {
                let mycopt = copt.take();
                let mut curr = mycopt.unwrap();
                // 'request' is earlier than current element, insert here by making
                // the current Option point to 'request' and have 'request''s next
                // Option point to the element the current Option held.
                if request.when < curr.when {
                   request.next = Some(curr);
                   *copt = Some(request);
                   done = true;
                } else {
                   // We need to insert later. We therefore are not inserting in
                   // the first element. There are two cases:
                   //   1. last element and we need to insert at the end, or
                   //   2. we need to traverse the next hop.
                   first = false;
                   if curr.next.is_none() {
                     // Reached end of list, insert here
                     curr.next = Some(request);
                     *copt = Some(curr);
                     done = true;
                   } else {
                     let mut nopt = &mut curr.next;
                     *copt = Some(curr);
                     copt = nopt;
                   }

                }
            }
            first
        }
    }

    /* Delete a TimerRequest from the linked list. Returns whether hardware
     * clock has to be recalculated (removed first timer) */
    fn delete(&mut self, request: &'static mut TimerRequest) -> bool {
        if self.request.is_none() {return false;}

        let mut done = false;
        let mut copt = &mut self.request;
        let mut first = true;
        while !done {
            let mycopt = copt.take();
            let mut curr = mycopt.unwrap();
            let cptr: *const TimerRequest = curr;
            let rptr: *const TimerRequest = request;
            if cptr == rptr {
                *copt = curr.next.take();
                done = true;
            } else if curr.next.is_none() {
                *copt = Some(curr);
                first = false;
                done = true;
            } else {
                let mut nopt = &mut curr.next;
                *copt = Some(curr);
                copt = nopt;
                first = false;
            }
        }
        first
    }

    /* Schedule the hardware alarm based on the first TimerRequest.
     * Assumes that timers are at most 2^31 in the future. If the
     * duration until a timer is > 2^31, assumes this means the
     * timer has passed (is late) and so fires immediately (in LATE_DELAY
     * ticks).
     */
    fn start_request(&mut self) {
        match self.request {
            Some(ref mut request) => {
                let mut when = request.when;
                let curr = self.internal.now();
                let delay = request.when - curr;
                if delay > (0x80000000) {
                    when = curr + LATE_DELAY;
                    request.when = when;
                }
                self.internal.set_alarm(when);
            },
            None => {}
        }
    }

}

impl alarm::AlarmClient for TimerMux {

    // The hardware alarm fired. If its firing matches the expected
    // firing time, invoke the next software timer and schedule the
    // following one.
    fn fired(&mut self) {
        if self.request.is_none() {return;}
        let curr = self.now();
        let ropt = self.request.take();
        let request: &'static mut TimerRequest = ropt.unwrap();
        // The timer did not fire early
        if (request.when - curr) < 20 {
            self.request = request.next.take();

            // Note this implementation is inefficient: if the repeat timer
            // would be at the head of the queue again, we recalculate the
            // timer, then re-insert so recalculate a second time.
            // A better implementation would check this and conditionally
            // remove/insert. -pal 7/22/15
            let cbopt = request.callback.take();
            let cb: &'static mut TimerCB = cbopt.unwrap();
            request.callback = Some(cb);
            if request.is_repeat {
                request.when = request.when + request.interval;
                self.add(request);
            } else {
                request.is_active = false;
            }
            self.start_request();
            cb.fired(request, curr);
        } else {
            // Timer fired early. Not sure why this happens,
            // But it does -pal 7/28/15
            self.request = Some(request);
            self.start_request();
        }
    }
}

impl Timer for TimerMux {
    fn now(&self) -> u32 {
        self.internal.now()
    }

    fn cancel(&mut self, request: &'static mut TimerRequest) {
        if !request.is_active {return;}

        request.is_active = false;
        self.remove(request);
    }

    fn oneshot(&mut self, interval: u32, request: &'static mut TimerRequest) {
        request.interval = interval;
        request.is_active = true;
        request.when = self.now() + interval;
        request.is_repeat = false;
        self.add(request);
    }

    fn repeat(&mut self, interval: u32, request: &'static mut TimerRequest) {
        request.interval = interval;
        request.is_active = true;
        request.when = self.now() + interval;
        request.is_repeat = true;
        self.add(request);
    }
}

<commit_msg>Avoid unsafe operationg in VirtualTimer<commit_after>/* hil::timer -- Traits and structures for software timers.
 *
 * Support for virtualized software timers on top of a single hardware
 * alarm (counter interrupt). Currently traits do not specify the time
 * units of the timers; a future version will.
 *
 * The four relevant types are:
 *   - Timer: the trait that provides virtualized timers
 *   - TimerMux: the struct that implements Timer on top of Alarm
 *   - TimerRequest: the structure a caller must pass in when requesting
 *                   a timer
 *   - TimerCB: the trait which has the callback for when the timer fires
 *
 * The TimerRequest structure contains a reference to a TimerCB. So
 * to invoke a timer, an application defines a structure that implements
 * TimerCB, creates a TimerRequest whose callback field is the TimerCB
 * (either through new() or initialization), then passes TimerRequest to
 * calls to Timer.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Author: Amit Levy <levya@cs.stanford.edu>
 * Date: 7/16/15
 */
#![allow(dead_code)]

use core::prelude::*;
use alarm;

// If a timer is late (was supposed to fire in the past), LATE_DELAY
// specifies how far in the future to fire it. This number needs to be
// > 1 in case the counter ticks between reading it and setting the
// overflow value. Set it to 5 just to be safe.
const LATE_DELAY: u32 = 5;

pub trait TimerCB {
    fn fired(&mut self, &'static mut TimerRequest, now: u32);
}

pub trait Timer {
    fn now(&self) -> u32;
    fn cancel(&mut self, &'static mut TimerRequest);
    fn oneshot(&mut self, interval: u32, &'static mut TimerRequest);
    fn repeat(&mut self, interval: u32, &'static mut TimerRequest);
}

pub struct TimerRequest {
    pub next: Option<&'static mut TimerRequest>,
    pub is_active: bool,
    pub is_repeat: bool,
    pub when: u32,
    pub interval: u32,
    pub callback: Option<&'static mut TimerCB>
}

impl TimerRequest {
    pub fn new(cb: &'static mut TimerCB) -> TimerRequest {
        TimerRequest {
            next:      None,
            is_active: false,
            is_repeat: false,
            when:      0,
            interval:  0,
            callback:  Some(cb)
        }
    }
}

pub struct VirtualTimer {
    request: Option<&'static mut TimerRequest>,
    internal: &'static mut Timer
}

impl VirtualTimer {
    pub fn new(timer: &'static mut Timer, req: &'static mut TimerRequest)
        -> VirtualTimer {
        VirtualTimer { request: Some(req), internal: timer }
    }

    pub fn repeat(&mut self, interval: u32) {
        self.request.take().map(|request| {
            self.request = Some(request);
            self.internal.repeat(interval, request);
        });
    }

    pub fn oneshot(&mut self, interval: u32) {
        self.request.take().map(|request| {
            self.request = Some(request);
            self.internal.oneshot(interval, request);
        });
    }

    pub fn cancel(&mut self) {
        self.request.take().map(|request| {
            self.request = Some(request);
            self.internal.cancel(request);
        });
    }

    pub fn now(&self) -> u32 {
        self.internal.now()
    }
}

pub struct TimerMux {
    request: Option<&'static mut TimerRequest>,
    internal: &'static mut alarm::Alarm
}

impl TimerMux {
    pub fn new(internal: &'static mut alarm::Alarm) -> TimerMux {
        TimerMux {
            request: None,
            internal: internal
        }
    }

    /*
     * There are two pairs of functions for manipulating the ordered
     * linked list of outstanding timers
     *
     *  insert/delete: operate on list, inserting or deleting an entry
     *  add/remove: operate on list, and reconfigure underlying hardware
     *              alarm if first element of list changes
     *
     * add/remove are wrappers around insert/delete.
     */

    /* Insert a TimerRequest into the linked list, reconfiguring the
     * hardware alarm if it is inserted as the first element. */
    fn add(&mut self, request: &'static mut TimerRequest) -> bool {
        let changed = self.insert(request);
        if changed {
            self.start_request();
        }
        changed
    }

    /* Remove a TimerRequest into the linked list, reconfiguring the
     * hardware alarm if it was the first element. */
    fn remove(&mut self, request: &'static mut TimerRequest) -> bool {
        let changed = self.delete(request);
        if changed {
            self.start_request();
        }
        changed
    }

    /* Insert a TimerRequest into the linked list. Returns whether hardware
    * clock has to be recalculated (inserted timer is now first timer) */
    fn insert(&mut self, request: &'static mut TimerRequest) -> bool {
        if request.next.is_some() { // Already on a list, this is an error!
            false
        } else if self.request.is_none() {
            self.request = Some(request);
            true
        } else {
            let mut first = true;
            let mut done = false;
            let mut copt = &mut self.request;
            while !done {
                let mycopt = copt.take();
                let mut curr = mycopt.unwrap();
                // 'request' is earlier than current element, insert here by making
                // the current Option point to 'request' and have 'request''s next
                // Option point to the element the current Option held.
                if request.when < curr.when {
                   request.next = Some(curr);
                   *copt = Some(request);
                   done = true;
                } else {
                   // We need to insert later. We therefore are not inserting in
                   // the first element. There are two cases:
                   //   1. last element and we need to insert at the end, or
                   //   2. we need to traverse the next hop.
                   first = false;
                   if curr.next.is_none() {
                     // Reached end of list, insert here
                     curr.next = Some(request);
                     *copt = Some(curr);
                     done = true;
                   } else {
                     let mut nopt = &mut curr.next;
                     *copt = Some(curr);
                     copt = nopt;
                   }

                }
            }
            first
        }
    }

    /* Delete a TimerRequest from the linked list. Returns whether hardware
     * clock has to be recalculated (removed first timer) */
    fn delete(&mut self, request: &'static mut TimerRequest) -> bool {
        if self.request.is_none() {return false;}

        let mut done = false;
        let mut copt = &mut self.request;
        let mut first = true;
        while !done {
            let mycopt = copt.take();
            let mut curr = mycopt.unwrap();
            let cptr: *const TimerRequest = curr;
            let rptr: *const TimerRequest = request;
            if cptr == rptr {
                *copt = curr.next.take();
                done = true;
            } else if curr.next.is_none() {
                *copt = Some(curr);
                first = false;
                done = true;
            } else {
                let mut nopt = &mut curr.next;
                *copt = Some(curr);
                copt = nopt;
                first = false;
            }
        }
        first
    }

    /* Schedule the hardware alarm based on the first TimerRequest.
     * Assumes that timers are at most 2^31 in the future. If the
     * duration until a timer is > 2^31, assumes this means the
     * timer has passed (is late) and so fires immediately (in LATE_DELAY
     * ticks).
     */
    fn start_request(&mut self) {
        match self.request {
            Some(ref mut request) => {
                let mut when = request.when;
                let curr = self.internal.now();
                let delay = request.when - curr;
                if delay > (0x80000000) {
                    when = curr + LATE_DELAY;
                    request.when = when;
                }
                self.internal.set_alarm(when);
            },
            None => {}
        }
    }

}

impl alarm::AlarmClient for TimerMux {

    // The hardware alarm fired. If its firing matches the expected
    // firing time, invoke the next software timer and schedule the
    // following one.
    fn fired(&mut self) {
        if self.request.is_none() {return;}
        let curr = self.now();
        let ropt = self.request.take();
        let request: &'static mut TimerRequest = ropt.unwrap();
        // The timer did not fire early
        if (request.when - curr) < 20 {
            self.request = request.next.take();

            // Note this implementation is inefficient: if the repeat timer
            // would be at the head of the queue again, we recalculate the
            // timer, then re-insert so recalculate a second time.
            // A better implementation would check this and conditionally
            // remove/insert. -pal 7/22/15
            let cbopt = request.callback.take();
            let cb: &'static mut TimerCB = cbopt.unwrap();
            request.callback = Some(cb);
            if request.is_repeat {
                request.when = request.when + request.interval;
                self.add(request);
            } else {
                request.is_active = false;
            }
            self.start_request();
            cb.fired(request, curr);
        } else {
            // Timer fired early. Not sure why this happens,
            // But it does -pal 7/28/15
            self.request = Some(request);
            self.start_request();
        }
    }
}

impl Timer for TimerMux {
    fn now(&self) -> u32 {
        self.internal.now()
    }

    fn cancel(&mut self, request: &'static mut TimerRequest) {
        if !request.is_active {return;}

        request.is_active = false;
        self.remove(request);
    }

    fn oneshot(&mut self, interval: u32, request: &'static mut TimerRequest) {
        request.interval = interval;
        request.is_active = true;
        request.when = self.now() + interval;
        request.is_repeat = false;
        self.add(request);
    }

    fn repeat(&mut self, interval: u32, request: &'static mut TimerRequest) {
        request.interval = interval;
        request.is_active = true;
        request.when = self.now() + interval;
        request.is_repeat = true;
        self.add(request);
    }
}

<|endoftext|>


<commit_before>/// Constructs a query that finds record(s) based on directional association with other record(s).
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # #[macro_use] extern crate diesel_codegen;
/// # include!("../doctest_setup.rs");
/// # use schema::{posts, users};
/// #
/// # #[derive(Identifiable, Queryable)]
/// # pub struct User {
/// #     id: i32,
/// #     name: String,
/// # }
/// #
/// # #[derive(Debug, PartialEq)]
/// # #[derive(Identifiable, Queryable, Associations)]
/// # #[belongs_to(User)]
/// # pub struct Post {
/// #     id: i32,
/// #     user_id: i32,
/// #     title: String,
/// # }
/// #
/// # fn main() {
/// # let connection = establish_connection();
/// # use users::dsl::*;
/// # let user = users.find(2).get_result::<User>(&connection).unwrap();
/// let posts = Post::belonging_to(&user)
/// #    .load::<Post>(&connection);
/// #
/// # assert_eq!(posts,
/// #     Ok(vec![Post { id: 3, user_id: 2, title: "My first post too".to_owned() }])
/// # );
/// # }
/// ```
pub trait BelongingToDsl<T> {
    /// The query returned by `belonging_to`
    type Output;

    /// Get the record(s) belonging to record(s) `other`
    fn belonging_to(other: T) -> Self::Output;
}
<commit_msg>Add deny docs to query_dsl/belonging_to_dsl<commit_after>#![deny(missing_docs)]
/// Constructs a query that finds record(s) based on directional association with other record(s).
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # #[macro_use] extern crate diesel_codegen;
/// # include!("../doctest_setup.rs");
/// # use schema::{posts, users};
/// #
/// # #[derive(Identifiable, Queryable)]
/// # pub struct User {
/// #     id: i32,
/// #     name: String,
/// # }
/// #
/// # #[derive(Debug, PartialEq)]
/// # #[derive(Identifiable, Queryable, Associations)]
/// # #[belongs_to(User)]
/// # pub struct Post {
/// #     id: i32,
/// #     user_id: i32,
/// #     title: String,
/// # }
/// #
/// # fn main() {
/// # let connection = establish_connection();
/// # use users::dsl::*;
/// # let user = users.find(2).get_result::<User>(&connection).unwrap();
/// let posts = Post::belonging_to(&user)
/// #    .load::<Post>(&connection);
/// #
/// # assert_eq!(posts,
/// #     Ok(vec![Post { id: 3, user_id: 2, title: "My first post too".to_owned() }])
/// # );
/// # }
/// ```
pub trait BelongingToDsl<T> {
    /// The query returned by `belonging_to`
    type Output;

    /// Get the record(s) belonging to record(s) `other`
    fn belonging_to(other: T) -> Self::Output;
}
<|endoftext|>


<commit_before><commit_msg>Format code<commit_after><|endoftext|>


<commit_before><commit_msg>- add alias for stack numeric value - upd operators priority - chg '<-' to '=' operator - add stack function (for see available variables)<commit_after><|endoftext|>


<commit_before><commit_msg>Remove unreachable code, fixes #11<commit_after><|endoftext|>