<commit_before>// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0
#![cfg(feature = "runtime-testing")]

use heck::CamelCase;
use serde_generate::{
    csharp, test_utils,
    test_utils::{Choice, Runtime, Test},
    CodeGeneratorConfig, SourceInstaller,
};
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::Mutex;

lazy_static::lazy_static! {
    // `dotnet build` spuriously fails on linux if run concurrently
    static ref MUTEX: Mutex<()> = Mutex::new(());
}

/// Returns:
/// 1. A `PathBuf` to the directory to write test data into
/// 2. Optionally, a `tempfile::TempDir` which deletes the directory when it goes out of scope
fn create_test_dir(test_name: &'static str) -> (PathBuf, Option<tempfile::TempDir>) {
    // Set env var to generate into subdirectories for inspection
    if std::env::var("TEST_USE_SUBDIR").is_ok() {
        let mut tries = 0;
        while tries < 20 {
            let test_dir_name = if tries == 0 {
                test_name.into()
            } else {
                format!("{}_{}", test_name, tries)
            };
            let dir = Path::new("tests").join(test_dir_name).to_path_buf();
            match std::fs::create_dir(&dir) {
                Ok(()) => return (dir, None),
                Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => tries += 1,
                Err(e) => panic!("Error creating test directory: {:?}", e),
            }
        }
        panic!("Error creating test directory: Too many existing test directories");
    } else {
        let tempdir = tempfile::Builder::new()
            .suffix(&format!("_{}", test_name))
            .tempdir()
            .unwrap();
        (tempdir.path().to_path_buf(), Some(tempdir))
    }
}

fn dotnet_build(proj_dir: &Path) {
    let _lock = MUTEX.lock();
    let status = Command::new("dotnet")
        .arg("build")
        .current_dir(proj_dir)
        .status()
        .unwrap();
    assert!(status.success());
}

fn run_nunit(proj_dir: &Path) {
    let _lock = MUTEX.lock();
    let status = Command::new("dotnet")
        .arg("test")
        .current_dir(proj_dir)
        .status()
        .unwrap();
    assert!(status.success());
}

fn copy_test_project(root_dir: &Path, copy_runtime_tests: bool) -> PathBuf {
    let test_dir = root_dir.join("Serde.Tests").to_path_buf();

    std::fs::create_dir(&test_dir).unwrap();
    std::fs::copy(
        "runtime/csharp/Serde.Tests/Serde.Tests.csproj",
        &test_dir.join("Serde.Tests.csproj"),
    )
    .unwrap();

    if copy_runtime_tests {
        std::fs::copy(
            "runtime/csharp/Serde.Tests/TestLcs.cs",
            &test_dir.join("TestLcs.cs"),
        )
        .unwrap();
    }

    test_dir
}

#[test]
fn test_csharp_lcs_runtime_tests() {
    let (dir, _tmp) = create_test_dir("test_csharp_lcs_runtime_tests");
    let test_dir = copy_test_project(&dir, true);

    let installer = csharp::Installer::new(dir);
    installer.install_serde_runtime().unwrap();
    installer.install_lcs_runtime().unwrap();

    dotnet_build(&test_dir);
    run_nunit(&test_dir);
}

#[test]
fn test_csharp_lcs_runtime_on_simple_data() {
    let (dir, _tmp) = create_test_dir("test_csharp_runtime_on_simple_data");
    test_csharp_runtime_on_simple_data(dir, Runtime::Lcs);
}

#[test]
fn test_csharp_bincode_runtime_on_simple_data() {
    let (dir, _tmp) = create_test_dir("test_csharp_bincode_runtime_on_simple_data");
    test_csharp_runtime_on_simple_data(dir, Runtime::Bincode);
}

fn test_csharp_runtime_on_simple_data(dir: PathBuf, runtime: Runtime) {
    let test_dir = copy_test_project(&dir, false);

    let registry = test_utils::get_simple_registry().unwrap();

    let installer = csharp::Installer::new(dir.clone());
    installer.install_serde_runtime().unwrap();
    installer.install_bincode_runtime().unwrap();
    installer.install_lcs_runtime().unwrap();

    // Generates code into `Serde/Tests`
    let config =
        CodeGeneratorConfig::new("Serde.Tests".to_string()).with_encodings(vec![runtime.into()]);
    let generator = csharp::CodeGenerator::new(&config);
    generator.write_source_files(dir, &registry).unwrap();

    let reference = runtime.serialize(&Test {
        a: vec![4, 6],
        b: (-3, 5),
        c: Choice::C { x: 7 },
    });

    let mut source = File::create(&test_dir.join("TestRuntime.cs")).unwrap();
    writeln!(
        source,
        r#"
using System;
using System.Collections.Generic;
using System.IO;
using NUnit.Framework;

namespace Serde.Tests {{
    public class TestRuntime {{
        [Test]
        public void TestRoundTrip() {{
            byte[] input = new byte[] {{{0}}};

            Test test = Test.{1}Deserialize(input);

            List<uint> a = new List<uint>(new uint[] {{ 4, 6 }});
            var b = ((long)-3, (ulong)5);
            Choice c = new Choice.C((byte) 7);
            Test test2 = new Test(a, b, c);

            Assert.AreEqual(test, test2);

            byte[] output = test2.{1}Serialize();

            CollectionAssert.AreEqual(input, output);

            byte[] input2 = new byte[] {{{0}, 1}};
            Assert.Throws<DeserializationException>(() => Test.{1}Deserialize(input2));
        }}
    }}
}}
"#,
        reference
            .iter()
            .map(|x| format!("{}", *x as u8))
            .collect::<Vec<_>>()
            .join(", "),
        runtime.name().to_camel_case(),
    )
    .unwrap();

    dotnet_build(&test_dir);
    run_nunit(&test_dir);
}

#[test]
fn test_csharp_lcs_runtime_on_supported_types() {
    let (dir, _tmp) = create_test_dir("test_csharp_lcs_runtime_on_supported_types");
    test_csharp_runtime_on_supported_types(dir, Runtime::Lcs);
}

#[test]
fn test_csharp_bincode_runtime_on_supported_types() {
    let (dir, _tmp) = create_test_dir("test_csharp_bincode_runtime_on_supported_types");
    test_csharp_runtime_on_supported_types(dir, Runtime::Bincode);
}

fn quote_bytes(bytes: &[u8]) -> String {
    format!(
        "{{{}}}",
        bytes
            .iter()
            .map(|x| format!("{}", *x as u8))
            .collect::<Vec<_>>()
            .join(", ")
    )
}

fn test_csharp_runtime_on_supported_types(dir: PathBuf, runtime: Runtime) {
    let test_dir = copy_test_project(&dir, false);

    let registry = test_utils::get_registry().unwrap();

    let installer = csharp::Installer::new(dir.clone());
    installer.install_serde_runtime().unwrap();
    installer.install_bincode_runtime().unwrap();
    installer.install_lcs_runtime().unwrap();

    // Generates code into `Serde/Tests`
    let config =
        CodeGeneratorConfig::new("Serde.Tests".to_string()).with_encodings(vec![runtime.into()]);
    let generator = csharp::CodeGenerator::new(&config);
    generator.write_source_files(dir, &registry).unwrap();

    let positive_encodings = runtime
        .get_positive_samples_quick()
        .iter()
        .map(|bytes| quote_bytes(bytes))
        .collect::<Vec<_>>();

    let negative_encodings = runtime
        .get_negative_samples()
        .iter()
        .map(|bytes| quote_bytes(bytes))
        .collect::<Vec<_>>();

    let mut source = File::create(test_dir.join("TestRuntime.cs")).unwrap();
    writeln!(
        source,
        r#"
using System;
using System.Linq;
using System.IO;
using NUnit.Framework;

namespace Serde.Tests {{
    public class TestRuntime {{
        static void TestPassInput(byte[] input) {{
            SerdeData test = SerdeData.{0}Deserialize(input);
            byte[] output = test.{0}Serialize();

            CollectionAssert.AreEqual(input, output);

            // Test simple mutations of the input.
            for (int i = 0; i < input.Length; i++) {{
                byte[] input2 = input.ToArray();
                input2[i] ^= 0x80;
                SerdeData test2;
                try {{
                    test2 = SerdeData.{0}Deserialize(input2);
                }}
                catch (Exception) {{ continue; }}
                Assert.AreNotEqual(test2, test);
            }}
        }}"#,
        runtime.name().to_camel_case()
    )
    .unwrap();

    for (i, input) in positive_encodings.iter().enumerate() {
        writeln!(
            source,
            r#"
        [Test]
        public void TestPassInput{0}() {{
            byte[] input = new byte[] {1};
            TestPassInput(input);
        }}"#,
            i, input
        )
        .unwrap();
    }

    for (i, input) in negative_encodings.iter().enumerate() {
        writeln!(
            source,
            r#"
        [Test]
        public void TestFailInput{0}() {{
            byte[] input = new byte[] {1};
            Assert.Catch(() => SerdeData.{2}Deserialize(input));
        }}"#,
            i,
            input,
            runtime.name().to_camel_case()
        )
        .unwrap();
    }

    writeln!(source, "\t}}\n}}\n").unwrap();

    dotnet_build(&test_dir);
    run_nunit(&test_dir);
}
<commit_msg>csharp: No longer need runtime-testing<commit_after>// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0

use heck::CamelCase;
use serde_generate::{
    csharp, test_utils,
    test_utils::{Choice, Runtime, Test},
    CodeGeneratorConfig, SourceInstaller,
};
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::Mutex;

lazy_static::lazy_static! {
    // `dotnet build` spuriously fails on linux if run concurrently
    static ref MUTEX: Mutex<()> = Mutex::new(());
}

/// Returns:
/// 1. A `PathBuf` to the directory to write test data into
/// 2. Optionally, a `tempfile::TempDir` which deletes the directory when it goes out of scope
fn create_test_dir(test_name: &'static str) -> (PathBuf, Option<tempfile::TempDir>) {
    // Set env var to generate into subdirectories for inspection
    if std::env::var("TEST_USE_SUBDIR").is_ok() {
        let mut tries = 0;
        while tries < 20 {
            let test_dir_name = if tries == 0 {
                test_name.into()
            } else {
                format!("{}_{}", test_name, tries)
            };
            let dir = Path::new("tests").join(test_dir_name).to_path_buf();
            match std::fs::create_dir(&dir) {
                Ok(()) => return (dir, None),
                Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => tries += 1,
                Err(e) => panic!("Error creating test directory: {:?}", e),
            }
        }
        panic!("Error creating test directory: Too many existing test directories");
    } else {
        let tempdir = tempfile::Builder::new()
            .suffix(&format!("_{}", test_name))
            .tempdir()
            .unwrap();
        (tempdir.path().to_path_buf(), Some(tempdir))
    }
}

fn dotnet_build(proj_dir: &Path) {
    let _lock = MUTEX.lock();
    let status = Command::new("dotnet")
        .arg("build")
        .current_dir(proj_dir)
        .status()
        .unwrap();
    assert!(status.success());
}

fn run_nunit(proj_dir: &Path) {
    let _lock = MUTEX.lock();
    let status = Command::new("dotnet")
        .arg("test")
        .current_dir(proj_dir)
        .status()
        .unwrap();
    assert!(status.success());
}

fn copy_test_project(root_dir: &Path, copy_runtime_tests: bool) -> PathBuf {
    let test_dir = root_dir.join("Serde.Tests").to_path_buf();

    std::fs::create_dir(&test_dir).unwrap();
    std::fs::copy(
        "runtime/csharp/Serde.Tests/Serde.Tests.csproj",
        &test_dir.join("Serde.Tests.csproj"),
    )
    .unwrap();

    if copy_runtime_tests {
        std::fs::copy(
            "runtime/csharp/Serde.Tests/TestLcs.cs",
            &test_dir.join("TestLcs.cs"),
        )
        .unwrap();
    }

    test_dir
}

#[test]
fn test_csharp_lcs_runtime_tests() {
    let (dir, _tmp) = create_test_dir("test_csharp_lcs_runtime_tests");
    let test_dir = copy_test_project(&dir, true);

    let installer = csharp::Installer::new(dir);
    installer.install_serde_runtime().unwrap();
    installer.install_lcs_runtime().unwrap();

    dotnet_build(&test_dir);
    run_nunit(&test_dir);
}

#[test]
fn test_csharp_lcs_runtime_on_simple_data() {
    let (dir, _tmp) = create_test_dir("test_csharp_runtime_on_simple_data");
    test_csharp_runtime_on_simple_data(dir, Runtime::Lcs);
}

#[test]
fn test_csharp_bincode_runtime_on_simple_data() {
    let (dir, _tmp) = create_test_dir("test_csharp_bincode_runtime_on_simple_data");
    test_csharp_runtime_on_simple_data(dir, Runtime::Bincode);
}

fn test_csharp_runtime_on_simple_data(dir: PathBuf, runtime: Runtime) {
    let test_dir = copy_test_project(&dir, false);

    let registry = test_utils::get_simple_registry().unwrap();

    let installer = csharp::Installer::new(dir.clone());
    installer.install_serde_runtime().unwrap();
    installer.install_bincode_runtime().unwrap();
    installer.install_lcs_runtime().unwrap();

    // Generates code into `Serde/Tests`
    let config =
        CodeGeneratorConfig::new("Serde.Tests".to_string()).with_encodings(vec![runtime.into()]);
    let generator = csharp::CodeGenerator::new(&config);
    generator.write_source_files(dir, &registry).unwrap();

    let reference = runtime.serialize(&Test {
        a: vec![4, 6],
        b: (-3, 5),
        c: Choice::C { x: 7 },
    });

    let mut source = File::create(&test_dir.join("TestRuntime.cs")).unwrap();
    writeln!(
        source,
        r#"
using System;
using System.Collections.Generic;
using System.IO;
using NUnit.Framework;

namespace Serde.Tests {{
    public class TestRuntime {{
        [Test]
        public void TestRoundTrip() {{
            byte[] input = new byte[] {{{0}}};

            Test test = Test.{1}Deserialize(input);

            List<uint> a = new List<uint>(new uint[] {{ 4, 6 }});
            var b = ((long)-3, (ulong)5);
            Choice c = new Choice.C((byte) 7);
            Test test2 = new Test(a, b, c);

            Assert.AreEqual(test, test2);

            byte[] output = test2.{1}Serialize();

            CollectionAssert.AreEqual(input, output);

            byte[] input2 = new byte[] {{{0}, 1}};
            Assert.Throws<DeserializationException>(() => Test.{1}Deserialize(input2));
        }}
    }}
}}
"#,
        reference
            .iter()
            .map(|x| format!("{}", *x as u8))
            .collect::<Vec<_>>()
            .join(", "),
        runtime.name().to_camel_case(),
    )
    .unwrap();

    dotnet_build(&test_dir);
    run_nunit(&test_dir);
}

#[test]
fn test_csharp_lcs_runtime_on_supported_types() {
    let (dir, _tmp) = create_test_dir("test_csharp_lcs_runtime_on_supported_types");
    test_csharp_runtime_on_supported_types(dir, Runtime::Lcs);
}

#[test]
fn test_csharp_bincode_runtime_on_supported_types() {
    let (dir, _tmp) = create_test_dir("test_csharp_bincode_runtime_on_supported_types");
    test_csharp_runtime_on_supported_types(dir, Runtime::Bincode);
}

fn quote_bytes(bytes: &[u8]) -> String {
    format!(
        "{{{}}}",
        bytes
            .iter()
            .map(|x| format!("{}", *x as u8))
            .collect::<Vec<_>>()
            .join(", ")
    )
}

fn test_csharp_runtime_on_supported_types(dir: PathBuf, runtime: Runtime) {
    let test_dir = copy_test_project(&dir, false);

    let registry = test_utils::get_registry().unwrap();

    let installer = csharp::Installer::new(dir.clone());
    installer.install_serde_runtime().unwrap();
    installer.install_bincode_runtime().unwrap();
    installer.install_lcs_runtime().unwrap();

    // Generates code into `Serde/Tests`
    let config =
        CodeGeneratorConfig::new("Serde.Tests".to_string()).with_encodings(vec![runtime.into()]);
    let generator = csharp::CodeGenerator::new(&config);
    generator.write_source_files(dir, &registry).unwrap();

    let positive_encodings = runtime
        .get_positive_samples_quick()
        .iter()
        .map(|bytes| quote_bytes(bytes))
        .collect::<Vec<_>>();

    let negative_encodings = runtime
        .get_negative_samples()
        .iter()
        .map(|bytes| quote_bytes(bytes))
        .collect::<Vec<_>>();

    let mut source = File::create(test_dir.join("TestRuntime.cs")).unwrap();
    writeln!(
        source,
        r#"
using System;
using System.Linq;
using System.IO;
using NUnit.Framework;

namespace Serde.Tests {{
    public class TestRuntime {{
        static void TestPassInput(byte[] input) {{
            SerdeData test = SerdeData.{0}Deserialize(input);
            byte[] output = test.{0}Serialize();

            CollectionAssert.AreEqual(input, output);

            // Test simple mutations of the input.
            for (int i = 0; i < input.Length; i++) {{
                byte[] input2 = input.ToArray();
                input2[i] ^= 0x80;
                SerdeData test2;
                try {{
                    test2 = SerdeData.{0}Deserialize(input2);
                }}
                catch (Exception) {{ continue; }}
                Assert.AreNotEqual(test2, test);
            }}
        }}"#,
        runtime.name().to_camel_case()
    )
    .unwrap();

    for (i, input) in positive_encodings.iter().enumerate() {
        writeln!(
            source,
            r#"
        [Test]
        public void TestPassInput{0}() {{
            byte[] input = new byte[] {1};
            TestPassInput(input);
        }}"#,
            i, input
        )
        .unwrap();
    }

    for (i, input) in negative_encodings.iter().enumerate() {
        writeln!(
            source,
            r#"
        [Test]
        public void TestFailInput{0}() {{
            byte[] input = new byte[] {1};
            Assert.Catch(() => SerdeData.{2}Deserialize(input));
        }}"#,
            i,
            input,
            runtime.name().to_camel_case()
        )
        .unwrap();
    }

    writeln!(source, "\t}}\n}}\n").unwrap();

    dotnet_build(&test_dir);
    run_nunit(&test_dir);
}
<|endoftext|>


<commit_before>//! Implements inter-function reference propagation
//!
//! Design points:
//!   - Keep the generic case in mind. The inter-function propagation should, in theory, work
//!   with any generic intra-function analysis. This allows us reuse code whenever the general
//!   structure of the analysis is same.
//!

use frontend::radeco_containers::{RadecoFunction, RadecoModule};
use middle::ir::MAddress;
use middle::regfile::SubRegisterFile;
use r2api::structs::LSectionInfo;
use rayon::prelude::*;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::Arc;
use petgraph::visit::EdgeRef;
use petgraph::Direction;

pub trait InterProcAnalysis: Transfer + Propagate {}

impl<T: Transfer + Propagate> InterProcAnalysis for T {}

pub trait Transfer {
    // Generalize to take anything (any information about the context/module)
    // This function is only called the first time the analysis is executed. This function then
    // returns `Self` that contains (partially-)analyzed information.
    fn transfer(&mut RadecoFunction, &SubRegisterFile, &[LSectionInfo]) -> Self;
    // Called when transfer function needs to be executed iteratively.
    // This function returns a `bool` which indicates if the analysis made any progress on this
    // iteration of call.
    fn transfer_iterative(&mut Self, &mut RadecoFunction) -> bool;
}

pub trait Propagate {
    type Info: Default + Eval;
    // Used to `pull` information, `Info`, relevant in inter-proc analysis computed in
    // the transfer phase.
    fn pull(&mut Self, &RadecoFunction, u64) -> Option<Self::Info>;
    fn summary(&mut Self) -> Option<Self::Info>;
    // Used to aggregate information obtained from various sources/callsites
    fn union(&mut Self, &[Self::Info]) -> Option<Self::Info>;
    // Used to `push` information to the analyzer based on computed InterProc information.
    // Returns true if something in the internal state of the analyzer changed. This could be used
    // as a hint to determine if the analyzer can make further progress.
    fn push(&mut Self, Option<&Self::Info>) -> bool;
}

// TODO: Maybe `Eval` can be a part of definition of a lattice later on.
pub trait Eval: Default {
    fn eval(&Self, &Self) -> Self;
}

// TODO: Move to a more appropriate place, i.e. `radeco_containers.rs`, once the details are
// concrete.
pub struct CallSite<T> {
    site: MAddress,
    info: T,
}

// TODO: Think about implementing this on top of the trait directly rather than a dummy struct
struct InterProceduralAnalyzer<T: InterProcAnalysis> {
    _t: PhantomData<T>,
}

impl<T: InterProcAnalysis> InterProceduralAnalyzer<T> {
    pub fn analyze(rmod: &mut RadecoModule, regfile: &SubRegisterFile, n_iters: Option<u64>) {
        let sections = Arc::clone(rmod.sections());
        let mut analyzers: Vec<(u64, T)> = Vec::new();
        let mut fixpoint = false;

        // Transfer can be done in (TODO) parallel
        for wrapper in rmod.iter_mut() {
            let (current_offset, current_fn) = wrapper.function;
            let analyzer = T::transfer(current_fn, &regfile, &sections);
            analyzers.push((*current_offset, analyzer));
        }

        // TODO: Set fixpoint correctly
        while !fixpoint {
            // Propagation should be done in serial
            let mut infos: HashMap<u64, Vec<T::Info>> = HashMap::new();
            for (i, wrapper) in rmod.iter().enumerate() {
                let (current_offset, current_fn) = wrapper.function;
                let &mut (_, ref mut current_analyzer) = analyzers.get_mut(i).expect("");
                // Get info about current function
                if let Some(this_info) = T::summary(current_analyzer) {
                    infos.entry(*current_offset).or_insert(Vec::new()).push(this_info);
                }
                // Get callsite information for every callee of current function
                let callgraph = rmod.callgraph();
                let current_fn_node = current_fn.cgid();
                for (callee, info) in callgraph
                    .edges_directed(current_fn_node, Direction::Outgoing)
                    .map(|call_edge| {
                        let callee = *callgraph.node_weight(call_edge.target()).expect("");
                        let csite = *call_edge.weight();
                        (callee, T::pull(current_analyzer, current_fn, csite))
                    }) {
                    infos.entry(callee).or_insert(Vec::new()).push(info.unwrap_or_default());
                }
            }

            // Union all infos collected for a function. TODO: Parallelize as there is no
            // dependency.
            for (_, infov) in infos.iter_mut() {
                // XXX: Avoid allocation
                *infov = vec![infov.iter()
                                  .fold(T::Info::default(), |acc, x| T::Info::eval(&acc, &x))];
            }

            // Push the information down to the analyzers.
            for &mut(offset, ref mut analyzer) in analyzers.iter_mut() {
                let info = infos.get(&offset);
                if let Some(ref inf) = info {
                    T::push(analyzer, Some(&inf[0]));
                }
            }

            // Continue analysis. TODO: Parallelize
            for (wrapper, aw) in rmod.iter_mut().zip(analyzers.iter_mut()) {
                let &mut(_, ref mut analyzer) = aw;
                let (_, current_fn) = wrapper.function;
                T::transfer_iterative(analyzer, current_fn);
            }
        }
    }
}
<commit_msg>Minor improvements to interproc analyzer<commit_after>//! Implements inter-function reference propagation
//!
//! Design points:
//!   - Keep the generic case in mind. The inter-function propagation should, in theory, work
//!   with any generic intra-function analysis. This allows us reuse code whenever the general
//!   structure of the analysis is same.
//!

use frontend::radeco_containers::{RadecoFunction, RadecoModule};
use middle::ir::MAddress;
use middle::regfile::SubRegisterFile;
use r2api::structs::LSectionInfo;
use rayon::prelude::*;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::Arc;
use petgraph::visit::EdgeRef;
use petgraph::Direction;

pub trait InterProcAnalysis: Transfer + Propagate {}

impl<T: Transfer + Propagate> InterProcAnalysis for T {}

pub trait Transfer {
    // Generalize to take anything (any information about the context/module)
    // This function is only called the first time the analysis is executed. This function then
    // returns `Self` that contains (partially-)analyzed information.
    fn transfer(&mut RadecoFunction, &SubRegisterFile, &[LSectionInfo]) -> Self;
    // Called when transfer function needs to be executed iteratively.
    // This function returns a `bool` which indicates if the analysis made any progress on this
    // iteration of call.
    fn transfer_iterative(&mut Self, &mut RadecoFunction) -> bool;
}

pub trait Propagate {
    type Info: Default + Eval;
    // Used to `pull` information, `Info`, relevant in inter-proc analysis computed in
    // the transfer phase.
    fn pull(&mut Self, &RadecoFunction, u64) -> Option<Self::Info>;
    fn summary(&mut Self) -> Option<Self::Info>;
    // Used to aggregate information obtained from various sources/callsites
    fn union(&mut Self, &[Self::Info]) -> Option<Self::Info>;
    // Used to `push` information to the analyzer based on computed InterProc information.
    // Returns true if something in the internal state of the analyzer changed. This could be used
    // as a hint to determine if the analyzer can make further progress.
    fn push(&mut Self, Option<&Self::Info>) -> bool;
}

// TODO: Maybe `Eval` can be a part of definition of a lattice later on.
pub trait Eval: Default {
    fn eval(&Self, &Self) -> Self;
}

// TODO: Move to a more appropriate place, i.e. `radeco_containers.rs`, once the details are
// concrete.
pub struct CallSite<T> {
    site: MAddress,
    info: T,
}

// TODO: Think about implementing this on top of the trait directly rather than a dummy struct
pub struct InterProceduralAnalyzer<T: InterProcAnalysis> {
    _t: PhantomData<T>,
}

struct AnalyzerWrapper<T: InterProcAnalysis> {
    analyzer: T,
    offset: u64,
    should_run: bool,
    times_run: u64,
}

impl<T: InterProcAnalysis> AnalyzerWrapper<T> {
    pub fn new(offset: u64, analyzer: T) -> AnalyzerWrapper<T> {
        AnalyzerWrapper {
            analyzer: analyzer,
            offset: offset,
            should_run: true,
            times_run: 0,
        }
    }

    pub fn analyzer_mut(&mut self) -> &mut T {
        &mut self.analyzer
    }

    pub fn analyzer(&self) -> &T {
        &self.analyzer
    }

    pub fn should_run(&self) -> bool {
        self.should_run
    }

    pub fn increment_run_count(&mut self) {
        self.times_run += 1;
    }

    pub fn offset(&self) -> u64 {
        self.offset
    }

    pub fn set_run(&mut self, should_run: bool) {
        self.should_run = should_run;
    }
}

impl<T: InterProcAnalysis> InterProceduralAnalyzer<T> {
    pub fn analyze(rmod: &mut RadecoModule, regfile: &SubRegisterFile, n_iters: Option<u64>) {
        let sections = Arc::clone(rmod.sections());
        let mut analyzers: Vec<AnalyzerWrapper<T>> = Vec::new();
        let mut fixpoint = false;

        // Transfer can be done in (TODO) parallel
        for wrapper in rmod.iter_mut() {
            let (current_offset, current_fn) = wrapper.function;
            let analyzer = T::transfer(current_fn, &regfile, &sections);
            analyzers.push(AnalyzerWrapper::new(*current_offset, analyzer));
        }

        while !fixpoint {
            // Propagation should be done in serial
            let mut infos: HashMap<u64, Vec<T::Info>> = HashMap::new();
            for (i, wrapper) in rmod.iter().enumerate() {
                let (current_offset, current_fn) = wrapper.function;
                let current_analyzer = analyzers.get_mut(i).map(|a| a.analyzer_mut()).expect("");
                // Get info about current function
                if let Some(this_info) = T::summary(current_analyzer) {
                    infos.entry(*current_offset).or_insert(Vec::new()).push(this_info);
                }
                // Get callsite information for every callee of current function
                let callgraph = rmod.callgraph();
                let current_fn_node = current_fn.cgid();
                for (callee, info) in callgraph
                    .edges_directed(current_fn_node, Direction::Outgoing)
                    .map(|call_edge| {
                        let callee = *callgraph.node_weight(call_edge.target()).expect("");
                        let csite = *call_edge.weight();
                        (callee, T::pull(current_analyzer, current_fn, csite))
                    }) {
                    infos.entry(callee).or_insert(Vec::new()).push(info.unwrap_or_default());
                }
            }

            // Union all infos collected for a function. TODO: Parallelize as there is no
            // dependency.
            for (_, infov) in infos.iter_mut() {
                // XXX: Avoid allocation
                *infov = vec![infov.iter()
                                .fold(T::Info::default(), |acc, x| T::Info::eval(&acc, &x))];
            }

            // Push the information down to the analyzers.
            for analyzer_wrapper in analyzers.iter_mut() {
                let offset = analyzer_wrapper.offset();
                analyzer_wrapper.should_run = {
                    let info = infos.get(&offset);
                    let analyzer = analyzer_wrapper.analyzer_mut();
                    if let Some(ref inf) = info {
                        T::push(analyzer, Some(&inf[0]))
                    } else {
                        // Assume that the analyzer should be run.
                        true
                    }
                }
            }

            // Continue analysis. TODO: Parallelize
            for (wrapper, aw) in rmod.iter_mut().zip(analyzers.iter_mut()) {
                // Check if the analyzer should be run for the current function.
                if !aw.should_run() { continue; }
                aw.increment_run_count();
                let analyzer = aw.analyzer_mut();
                let (_, current_fn) = wrapper.function;
                let fp = T::transfer_iterative(analyzer, current_fn);
                fixpoint = fixpoint || fp;
            }
        }
    }
}
<|endoftext|>


<commit_before>//! The half-lock structure
//!
//! We need a way to protect the structure with configured hooks ‒ a signal may happen in arbitrary
//! thread and needs to read them while another thread might be manipulating the structure.
//!
//! Under ordinary circumstances we would be happy to just use `Mutex<HashMap<c_int, _>>`. However,
//! as we use it in the signal handler, we are severely limited in what we can or can't use. So we
//! choose to implement kind of spin-look thing with atomics.
//!
//! In the reader it is always simply locked and then unlocked, making sure it doesn't disappear
//! while in use.
//!
//! The writer has a separate mutex (that prevents other writers; this is used outside of the
//! signal handler), makes a copy of the data and swaps an atomic pointer to the data structure.
//! But it waits until everything is unlocked (no signal handler has the old data) for dropping the
//! old instance. There's a generation trick to make sure that new signal locks another instance.
//!
//! The downside is, this is an active spin lock at the writer end. However, we assume than:
//!
//! * Signals are one time setup before we actually have threads. We just need to make *sure* we
//!   are safe even if this is not true.
//! * Signals are rare, happening at the same time as the write even rarer.
//! * Signals are short, as there is mostly nothing allowed inside them anyway.
//! * Our tool box is severely limited.
//!
//! Therefore this is hopefully reasonable trade-off.
//!
//! # Atomic orderings
//!
//! The whole code uses SeqCst conservatively. Atomics are not used because of performance here and
//! are the minor price around signals anyway. But the comments state which orderings should be
//! enough in practice in case someone wants to get inspired (but do make your own check through
//! them anyway).

use std::isize;
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering};
use std::sync::{Mutex, MutexGuard, PoisonError};
use std::thread;

const YIELD_EVERY: usize = 16;
const MAX_GUARDS: usize = (isize::MAX) as usize;

pub(crate) struct ReadGuard<'a, T: 'a> {
    data: &'a T,
    lock: &'a AtomicUsize,
}

impl<'a, T> Deref for ReadGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        self.data
    }
}

impl<'a, T> Drop for ReadGuard<'a, T> {
    fn drop(&mut self) {
        // We effectively unlock; Release would be enough.
        self.lock.fetch_sub(1, Ordering::SeqCst);
    }
}

pub(crate) struct WriteGuard<'a, T: 'a> {
    _guard: MutexGuard<'a, ()>,
    lock: &'a HalfLock<T>,
    data: &'a T,
}

impl<'a, T> WriteGuard<'a, T> {
    pub(crate) fn store(&mut self, val: T) {
        // Move to the heap and convert to raw pointer for AtomicPtr.
        let new = Box::into_raw(Box::new(val));

        self.data = unsafe { &*new };

        // We can just put the new value in here safely, we worry only about dropping the old one.
        // Release might (?) be enough, to "upload" the data.
        let old = self.lock.data.swap(new, Ordering::SeqCst);

        // Now we make sure there's no reader having the old data.
        self.lock.write_barrier();

        drop(unsafe { Box::from_raw(old) });
    }
}

impl<'a, T> Deref for WriteGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        // Protected by that mutex
        self.data
    }
}

pub(crate) struct HalfLock<T> {
    // We conceptually contain an instance of T
    _t: PhantomData<T>,
    // The actual data as a pointer.
    data: AtomicPtr<T>,
    // The generation of the data. Influences which slot of the lock counter we use.
    generation: AtomicUsize,
    // How many active locks are there?
    lock: [AtomicUsize; 2],
    // Mutex for the writers; only one writer.
    write_mutex: Mutex<()>,
}

impl<T> HalfLock<T> {
    pub(crate) fn new(data: T) -> Self {
        // Move to the heap so we can safely point there. Then convert to raw pointer as AtomicPtr
        // operates on raw pointers. The AtomicPtr effectively acts like Box for us semantically.
        let ptr = Box::into_raw(Box::new(data));
        Self {
            _t: PhantomData,
            data: AtomicPtr::new(ptr),
            generation: AtomicUsize::new(0),
            lock: [AtomicUsize::new(0), AtomicUsize::new(0)],
            write_mutex: Mutex::new(()),
        }
    }

    pub(crate) fn read(&self) -> ReadGuard<T> {
        // Relaxed should be enough; we only pick one or the other slot and the writer observes
        // that both were 0 at some time. So the actual value doesn't really matter for safety,
        // only the changing improves the performance.
        let gen = self.generation.load(Ordering::SeqCst);
        let lock = &self.lock[gen % 2];
        // Effectively locking something, acquire should be enough.
        let guard_cnt = lock.fetch_add(1, Ordering::SeqCst);

        // This is to prevent overflowing the counter in some degenerate cases, which could lead to
        // UB (freeing data while still in use). However, as this data structure is used only
        // internally and it's not possible to leak the guard and the guard itself takes some
        // memory, it should be really impossible to trigger this case. Still, we include it from
        // abundance of caution.
        //
        // This technically is not fully correct as enough threads being in between here and the
        // abort below could still overflow it and it could get freed for some *other* thread, but
        // that would mean having too many active threads to fit into RAM too and is even more
        // absurd corner case than the above.
        if guard_cnt > MAX_GUARDS {
            unsafe { libc::abort() };
        }

        // Acquire should be enough; we need to "download" the data, paired with the swap on the
        // same pointer.
        let data = self.data.load(Ordering::SeqCst);
        // Safe:
        // * It did point to valid data when put in.
        // * Protected by lock, so still valid.
        let data = unsafe { &*data };

        ReadGuard { data, lock }
    }

    fn update_seen(&self, seen_zero: &mut [bool; 2]) {
        for (seen, slot) in seen_zero.iter_mut().zip(&self.lock) {
            *seen = *seen || slot.load(Ordering::SeqCst) == 0;
        }
    }

    fn write_barrier(&self) {
        // Do a first check of seeing zeroes before we switch the generation. At least one of them
        // should be zero by now, due to having drained the generation before leaving the previous
        // writer.
        let mut seen_zero = [false; 2];
        self.update_seen(&mut seen_zero);
        // By switching the generation to the other slot, we make sure the currently active starts
        // draining while the other will start filling up.
        self.generation.fetch_add(1, Ordering::SeqCst); // Overflow is fine.

        let mut iter = 0usize;
        while !seen_zero.iter().all(|s| *s) {
            iter = iter.wrapping_add(1);

            // Be somewhat less aggressive while looping, switch to the other threads if possible.
            if cfg!(not(miri)) {
                if iter % YIELD_EVERY == 0 {
                    thread::yield_now();
                } else {
                    atomic::spin_loop_hint();
                }
            }

            self.update_seen(&mut seen_zero);
        }
    }

    pub(crate) fn write(&self) -> WriteGuard<T> {
        // While it's possible the user code panics, our code in store doesn't and the data gets
        // swapped atomically. So if it panics, nothing gets changed, therefore poisons are of no
        // interest here.
        let guard = self
            .write_mutex
            .lock()
            .unwrap_or_else(PoisonError::into_inner);

        // Relaxed should be enough, as we are under the same mutex that was used to get the data
        // in.
        let data = self.data.load(Ordering::SeqCst);
        // Safe:
        // * Stored as valid data
        // * Only this method, protected by mutex, can change the pointer, so it didn't go away.
        let data = unsafe { &*data };

        WriteGuard {
            data,
            _guard: guard,
            lock: self,
        }
    }
}

impl<T> Drop for HalfLock<T> {
    fn drop(&mut self) {
        // During drop we are sure there are no other borrows of the data so we are free to just
        // drop it. Also, the drop impl won't be called in practice in our case, as it is used
        // solely as a global variable, but we provide it for completeness and tests anyway.
        //
        // unsafe: the pointer in there is always valid, we just take the last instance out.
        unsafe {
            // Acquire should be enough.
            let data = Box::from_raw(self.data.load(Ordering::SeqCst));
            drop(data);
        }
    }
}
<commit_msg>Fix compilation on 1.26.0<commit_after>//! The half-lock structure
//!
//! We need a way to protect the structure with configured hooks ‒ a signal may happen in arbitrary
//! thread and needs to read them while another thread might be manipulating the structure.
//!
//! Under ordinary circumstances we would be happy to just use `Mutex<HashMap<c_int, _>>`. However,
//! as we use it in the signal handler, we are severely limited in what we can or can't use. So we
//! choose to implement kind of spin-look thing with atomics.
//!
//! In the reader it is always simply locked and then unlocked, making sure it doesn't disappear
//! while in use.
//!
//! The writer has a separate mutex (that prevents other writers; this is used outside of the
//! signal handler), makes a copy of the data and swaps an atomic pointer to the data structure.
//! But it waits until everything is unlocked (no signal handler has the old data) for dropping the
//! old instance. There's a generation trick to make sure that new signal locks another instance.
//!
//! The downside is, this is an active spin lock at the writer end. However, we assume than:
//!
//! * Signals are one time setup before we actually have threads. We just need to make *sure* we
//!   are safe even if this is not true.
//! * Signals are rare, happening at the same time as the write even rarer.
//! * Signals are short, as there is mostly nothing allowed inside them anyway.
//! * Our tool box is severely limited.
//!
//! Therefore this is hopefully reasonable trade-off.
//!
//! # Atomic orderings
//!
//! The whole code uses SeqCst conservatively. Atomics are not used because of performance here and
//! are the minor price around signals anyway. But the comments state which orderings should be
//! enough in practice in case someone wants to get inspired (but do make your own check through
//! them anyway).

use std::isize;
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering};
use std::sync::{Mutex, MutexGuard, PoisonError};
use std::thread;

use libc;

const YIELD_EVERY: usize = 16;
const MAX_GUARDS: usize = (isize::MAX) as usize;

pub(crate) struct ReadGuard<'a, T: 'a> {
    data: &'a T,
    lock: &'a AtomicUsize,
}

impl<'a, T> Deref for ReadGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        self.data
    }
}

impl<'a, T> Drop for ReadGuard<'a, T> {
    fn drop(&mut self) {
        // We effectively unlock; Release would be enough.
        self.lock.fetch_sub(1, Ordering::SeqCst);
    }
}

pub(crate) struct WriteGuard<'a, T: 'a> {
    _guard: MutexGuard<'a, ()>,
    lock: &'a HalfLock<T>,
    data: &'a T,
}

impl<'a, T> WriteGuard<'a, T> {
    pub(crate) fn store(&mut self, val: T) {
        // Move to the heap and convert to raw pointer for AtomicPtr.
        let new = Box::into_raw(Box::new(val));

        self.data = unsafe { &*new };

        // We can just put the new value in here safely, we worry only about dropping the old one.
        // Release might (?) be enough, to "upload" the data.
        let old = self.lock.data.swap(new, Ordering::SeqCst);

        // Now we make sure there's no reader having the old data.
        self.lock.write_barrier();

        drop(unsafe { Box::from_raw(old) });
    }
}

impl<'a, T> Deref for WriteGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        // Protected by that mutex
        self.data
    }
}

pub(crate) struct HalfLock<T> {
    // We conceptually contain an instance of T
    _t: PhantomData<T>,
    // The actual data as a pointer.
    data: AtomicPtr<T>,
    // The generation of the data. Influences which slot of the lock counter we use.
    generation: AtomicUsize,
    // How many active locks are there?
    lock: [AtomicUsize; 2],
    // Mutex for the writers; only one writer.
    write_mutex: Mutex<()>,
}

impl<T> HalfLock<T> {
    pub(crate) fn new(data: T) -> Self {
        // Move to the heap so we can safely point there. Then convert to raw pointer as AtomicPtr
        // operates on raw pointers. The AtomicPtr effectively acts like Box for us semantically.
        let ptr = Box::into_raw(Box::new(data));
        Self {
            _t: PhantomData,
            data: AtomicPtr::new(ptr),
            generation: AtomicUsize::new(0),
            lock: [AtomicUsize::new(0), AtomicUsize::new(0)],
            write_mutex: Mutex::new(()),
        }
    }

    pub(crate) fn read(&self) -> ReadGuard<T> {
        // Relaxed should be enough; we only pick one or the other slot and the writer observes
        // that both were 0 at some time. So the actual value doesn't really matter for safety,
        // only the changing improves the performance.
        let gen = self.generation.load(Ordering::SeqCst);
        let lock = &self.lock[gen % 2];
        // Effectively locking something, acquire should be enough.
        let guard_cnt = lock.fetch_add(1, Ordering::SeqCst);

        // This is to prevent overflowing the counter in some degenerate cases, which could lead to
        // UB (freeing data while still in use). However, as this data structure is used only
        // internally and it's not possible to leak the guard and the guard itself takes some
        // memory, it should be really impossible to trigger this case. Still, we include it from
        // abundance of caution.
        //
        // This technically is not fully correct as enough threads being in between here and the
        // abort below could still overflow it and it could get freed for some *other* thread, but
        // that would mean having too many active threads to fit into RAM too and is even more
        // absurd corner case than the above.
        if guard_cnt > MAX_GUARDS {
            unsafe { libc::abort() };
        }

        // Acquire should be enough; we need to "download" the data, paired with the swap on the
        // same pointer.
        let data = self.data.load(Ordering::SeqCst);
        // Safe:
        // * It did point to valid data when put in.
        // * Protected by lock, so still valid.
        let data = unsafe { &*data };

        ReadGuard { data, lock }
    }

    fn update_seen(&self, seen_zero: &mut [bool; 2]) {
        for (seen, slot) in seen_zero.iter_mut().zip(&self.lock) {
            *seen = *seen || slot.load(Ordering::SeqCst) == 0;
        }
    }

    fn write_barrier(&self) {
        // Do a first check of seeing zeroes before we switch the generation. At least one of them
        // should be zero by now, due to having drained the generation before leaving the previous
        // writer.
        let mut seen_zero = [false; 2];
        self.update_seen(&mut seen_zero);
        // By switching the generation to the other slot, we make sure the currently active starts
        // draining while the other will start filling up.
        self.generation.fetch_add(1, Ordering::SeqCst); // Overflow is fine.

        let mut iter = 0usize;
        while !seen_zero.iter().all(|s| *s) {
            iter = iter.wrapping_add(1);

            // Be somewhat less aggressive while looping, switch to the other threads if possible.
            if cfg!(not(miri)) {
                if iter % YIELD_EVERY == 0 {
                    thread::yield_now();
                } else {
                    atomic::spin_loop_hint();
                }
            }

            self.update_seen(&mut seen_zero);
        }
    }

    pub(crate) fn write(&self) -> WriteGuard<T> {
        // While it's possible the user code panics, our code in store doesn't and the data gets
        // swapped atomically. So if it panics, nothing gets changed, therefore poisons are of no
        // interest here.
        let guard = self
            .write_mutex
            .lock()
            .unwrap_or_else(PoisonError::into_inner);

        // Relaxed should be enough, as we are under the same mutex that was used to get the data
        // in.
        let data = self.data.load(Ordering::SeqCst);
        // Safe:
        // * Stored as valid data
        // * Only this method, protected by mutex, can change the pointer, so it didn't go away.
        let data = unsafe { &*data };

        WriteGuard {
            data,
            _guard: guard,
            lock: self,
        }
    }
}

impl<T> Drop for HalfLock<T> {
    fn drop(&mut self) {
        // During drop we are sure there are no other borrows of the data so we are free to just
        // drop it. Also, the drop impl won't be called in practice in our case, as it is used
        // solely as a global variable, but we provide it for completeness and tests anyway.
        //
        // unsafe: the pointer in there is always valid, we just take the last instance out.
        unsafe {
            // Acquire should be enough.
            let data = Box::from_raw(self.data.load(Ordering::SeqCst));
            drop(data);
        }
    }
}
<|endoftext|>


<commit_before>extern crate csv;

use super::pokemon_model;
use super::natures;
use super::enums;
use super::stats;
use super::determinant_values;
use super::movedex;
use super::moves;

use std::collections::HashMap;

///Represents a single Token of a Pokemon with individual values for this token.
#[derive(Debug, Clone)]
pub struct PokemonToken {
    pokedex_id: usize,
    name: String,
    level: u16,
    height: u8,
    weight: u16,
    gender: enums::Gender,
    type_one: enums::types,
    type_two: enums::types,
    non_volatile_status: (enums::Non_Volatile, u8),
    move_one: Option<(moves::Technique, u8)>,
    move_two: Option<(moves::Technique, u8)>,
    move_three: Option<(moves::Technique, u8)>,
    move_four: Option<(moves::Technique, u8)>,
    nature: natures::Nature,
    dv: determinant_values::Dv,
    base_stats: stats::Stats,
    current_stats: stats::Stats,
    end_of_turn_flags: HashMap<enums::End_Of_Turn, u8>,
    description: String,
    mega_evolution: Option<pokemon_model::PokemonModel>,
}

impl PokemonToken {
    ///Provides a Pokemon Token from a given model.
    pub fn from_model(model: pokemon_model::PokemonModel) -> PokemonToken {
        let level = 50;
        let dv = determinant_values::Dv::get_dvs(model.clone());
        let nature = natures::Nature::get_random_nature();
        let stats = stats::Stats::calculate_stats(model.clone(), dv.clone(), nature.clone(), level);

        PokemonToken {
            pokedex_id: model.get_id(),
            name: model.get_name(),
            level: level,
            height: model.get_height(),
            weight: model.get_weight(),
            gender: enums::get_gender(model.clone().get_gender_rate()),
            type_one: model.get_types().0,
            type_two: model.get_types().1,
            non_volatile_status: (enums::Non_Volatile::Undefined, 0),
            move_one: None,
            move_two: None,
            move_three: None,
            move_four: None,
            nature: nature,
            dv: dv,
            base_stats: stats.clone(),
            current_stats: stats,
            end_of_turn_flags: HashMap::new(),
            description: model.get_description(),
            mega_evolution: model.get_mega(),
        }
    }

    pub fn is_asleep(&self) -> bool {
        self.non_volatile_status.0 == enums::Non_Volatile::Sleep
    }

    pub fn get_moves(&self, dex: movedex::Movedex) -> movedex::Movedex {
        dex.for_token(self.get_level(), self.pokedex_id)
    }

    pub fn get_id(&self) -> usize {
        self.pokedex_id
    }

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

    pub fn get_level(&self) -> u16 {
        self.clone().level
    }

    pub fn get_gender(&self) -> enums::Gender {
        self.clone().gender
    }

    pub fn get_types(&self) -> (enums::types, enums::types) {
        (self.clone().type_one, self.clone().type_two)
    }

    pub fn get_nature(&self) -> natures::Nature {
        self.clone().nature
    }

    pub fn get_non_volatile(&self) ->(enums::Non_Volatile, u8) {
        self.clone().non_volatile_status
    }

    pub fn get_dv(&self) -> determinant_values::Dv {
        self.clone().dv
    }

    pub fn get_current(&self) -> stats::Stats {
        self.current_stats.clone()
    }

    pub fn get_base(&self) -> stats::Stats {
        self.base_stats.clone()
    }

    pub fn get_end_of_turn_flags(&self) -> HashMap<enums::End_Of_Turn, u8> {
        self.clone().end_of_turn_flags
    }

    pub fn get_mega(&self) -> Option<PokemonToken> {
        if self.mega_evolution.is_some() {
            return Some(PokemonToken::from_model(self.mega_evolution.clone().unwrap()));
        }
        None
    }

    /// Getter function for move one. If the move is set, the function returns it, if not,
    /// it returns None
    pub fn get_move_one(self) -> Option<moves::Technique> {
        Some(self.move_one.unwrap_or(return None).0)
    }
    /// Getter function for move two. If the move is set, the function returns it, if not,
    /// it returns None
    pub fn get_move_two(self) -> Option<moves::Technique> {
        Some(self.move_two.unwrap_or(return None).0)
    }
    /// Getter function for move three. If the move is set, the function returns it, if not,
    /// it returns None
    pub fn get_move_three(self) -> Option<moves::Technique> {
        Some(self.move_three.unwrap_or(return None).0)
    }
    /// Getter function for move four. If the move is set, the function returns it, if not,
    /// it returns None
    pub fn get_move_four(self) -> Option<moves::Technique> {
        Some(self.move_four.unwrap_or(return None).0)
    }

    pub fn set_non_volatile(&mut self, status: enums::Non_Volatile) {
        self.non_volatile_status = (status, 0);
    }

    pub fn add_end_flag(&mut self, flag: enums::End_Of_Turn) {
        self.end_of_turn_flags.insert(flag, 0);
    }

    pub fn set_moves(&mut self, moves: Vec<moves::Technique>) {
        self.move_one = Some((moves[0].clone(), moves[0].get_power_points().unwrap()));
        if moves.len() >= 1 {
            self.move_two = Some((moves[1].clone(), moves[1].get_power_points().unwrap()));
        }
        if moves.len() >= 2 {
            self.move_three = Some((moves[2].clone(), moves[2].get_power_points().unwrap()));
        }
        if moves.len() >= 3 {
            self.move_four = Some((moves[3].clone(), moves[3].get_power_points().unwrap()));
        }
    }

    pub fn set_type(&mut self, position: u8, change: enums::types) {
        match position {
            0 => self.type_one = change,
            1 => self.type_two = change,
            _ => unreachable!(),
        }
    }

    pub fn decrement_ap(&mut self) {
        unimplemented!();
    }
}
<commit_msg>fixed unwrap or in pokemon_token/ get_move_X functions<commit_after>extern crate csv;

use super::pokemon_model;
use super::natures;
use super::enums;
use super::stats;
use super::determinant_values;
use super::movedex;
use super::moves;

use std::collections::HashMap;

///Represents a single Token of a Pokemon with individual values for this token.
#[derive(Debug, Clone)]
pub struct PokemonToken {
    pokedex_id: usize,
    name: String,
    level: u16,
    height: u8,
    weight: u16,
    gender: enums::Gender,
    type_one: enums::types,
    type_two: enums::types,
    non_volatile_status: (enums::Non_Volatile, u8),
    move_one: Option<(moves::Technique, u8)>,
    move_two: Option<(moves::Technique, u8)>,
    move_three: Option<(moves::Technique, u8)>,
    move_four: Option<(moves::Technique, u8)>,
    nature: natures::Nature,
    dv: determinant_values::Dv,
    base_stats: stats::Stats,
    current_stats: stats::Stats,
    end_of_turn_flags: HashMap<enums::End_Of_Turn, u8>,
    description: String,
    mega_evolution: Option<pokemon_model::PokemonModel>,
}

impl PokemonToken {
    ///Provides a Pokemon Token from a given model.
    pub fn from_model(model: pokemon_model::PokemonModel) -> PokemonToken {
        let level = 50;
        let dv = determinant_values::Dv::get_dvs(model.clone());
        let nature = natures::Nature::get_random_nature();
        let stats = stats::Stats::calculate_stats(model.clone(), dv.clone(), nature.clone(), level);

        PokemonToken {
            pokedex_id: model.get_id(),
            name: model.get_name(),
            level: level,
            height: model.get_height(),
            weight: model.get_weight(),
            gender: enums::get_gender(model.clone().get_gender_rate()),
            type_one: model.get_types().0,
            type_two: model.get_types().1,
            non_volatile_status: (enums::Non_Volatile::Undefined, 0),
            move_one: None,
            move_two: None,
            move_three: None,
            move_four: None,
            nature: nature,
            dv: dv,
            base_stats: stats.clone(),
            current_stats: stats,
            end_of_turn_flags: HashMap::new(),
            description: model.get_description(),
            mega_evolution: model.get_mega(),
        }
    }

    pub fn is_asleep(&self) -> bool {
        self.non_volatile_status.0 == enums::Non_Volatile::Sleep
    }

    pub fn get_moves(&self, dex: movedex::Movedex) -> movedex::Movedex {
        dex.for_token(self.get_level(), self.pokedex_id)
    }

    pub fn get_id(&self) -> usize {
        self.pokedex_id
    }

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

    pub fn get_level(&self) -> u16 {
        self.clone().level
    }

    pub fn get_gender(&self) -> enums::Gender {
        self.clone().gender
    }

    pub fn get_types(&self) -> (enums::types, enums::types) {
        (self.clone().type_one, self.clone().type_two)
    }

    pub fn get_nature(&self) -> natures::Nature {
        self.clone().nature
    }

    pub fn get_non_volatile(&self) ->(enums::Non_Volatile, u8) {
        self.clone().non_volatile_status
    }

    pub fn get_dv(&self) -> determinant_values::Dv {
        self.clone().dv
    }

    pub fn get_current(&self) -> stats::Stats {
        self.current_stats.clone()
    }

    pub fn get_base(&self) -> stats::Stats {
        self.base_stats.clone()
    }

    pub fn get_end_of_turn_flags(&self) -> HashMap<enums::End_Of_Turn, u8> {
        self.clone().end_of_turn_flags
    }

    pub fn get_mega(&self) -> Option<PokemonToken> {
        if self.mega_evolution.is_some() {
            return Some(PokemonToken::from_model(self.mega_evolution.clone().unwrap()));
        }
        None
    }

    /// Getter function for move one. If the move is set, the function returns it, if not,
    /// it returns None
    pub fn get_move_one(self) -> Option<moves::Technique> {
        if let Some(x) = self.move_one {
            return Some(x.0);
        }
        None
    }
    /// Getter function for move two. If the move is set, the function returns it, if not,
    /// it returns None
    pub fn get_move_two(self) -> Option<moves::Technique> {
        if let Some(x) = self.move_two {
            return Some(x.0);
        }
        None
    }
    /// Getter function for move three. If the move is set, the function returns it, if not,
    /// it returns None
    pub fn get_move_three(self) -> Option<moves::Technique> {
        if let Some(x) = self.move_three {
            return Some(x.0);
        }
        None
    }
    /// Getter function for move four. If the move is set, the function returns it, if not,
    /// it returns None
    pub fn get_move_four(self) -> Option<moves::Technique> {
        if let Some(x) = self.move_four {
            return Some(x.0);
        }
        None
    }

    pub fn set_non_volatile(&mut self, status: enums::Non_Volatile) {
        self.non_volatile_status = (status, 0);
    }

    pub fn add_end_flag(&mut self, flag: enums::End_Of_Turn) {
        self.end_of_turn_flags.insert(flag, 0);
    }

    pub fn set_moves(&mut self, moves: Vec<moves::Technique>) {
        self.move_one = Some((moves[0].clone(), moves[0].get_power_points().unwrap()));
        if moves.len() >= 1 {
            self.move_two = Some((moves[1].clone(), moves[1].get_power_points().unwrap()));
        }
        if moves.len() >= 2 {
            self.move_three = Some((moves[2].clone(), moves[2].get_power_points().unwrap()));
        }
        if moves.len() >= 3 {
            self.move_four = Some((moves[3].clone(), moves[3].get_power_points().unwrap()));
        }
    }

    pub fn set_type(&mut self, position: u8, change: enums::types) {
        match position {
            0 => self.type_one = change,
            1 => self.type_two = change,
            _ => unreachable!(),
        }
    }

    pub fn decrement_ap(&mut self) {
        unimplemented!();
    }
}
<|endoftext|>


<commit_before>extern crate skeptic;

#[cfg(feature = "with-syntex")]
mod with_syntex {
    extern crate syntex;
    extern crate serde_codegen;
    extern crate indoc;

    use std::env;
    use std::path::Path;

    pub fn main() {
        let out_dir = env::var_os("OUT_DIR").unwrap();

        for &(src, dst) in &[
            ("tests/test.rs.in", "test.rs"),
            ("benches/bench.rs.in", "bench.rs"),
        ] {
            let src = Path::new(src);
            let dst = Path::new(&out_dir).join(dst);

            let mut registry = syntex::Registry::new();

            serde_codegen::register(&mut registry);
            indoc::register(&mut registry);
            registry.expand("", &src, &dst).unwrap();
        }
    }
}

#[cfg(not(feature = "with-syntex"))]
mod with_syntex {
    pub fn main() {}
}

pub fn main() {
    with_syntex::main();

    skeptic::generate_doc_tests(&["../README.md"]);
}
<commit_msg>Use serde_codegen::expand in json_tests/build.rs<commit_after>extern crate skeptic;

#[cfg(feature = "with-syntex")]
mod with_syntex {
    extern crate serde_codegen;
    extern crate indoc;

    use std::env;
    use std::path::Path;

    pub fn main() {
        let out_dir = env::var_os("OUT_DIR").unwrap();

        for &(src, dst) in &[
            ("tests/test.rs.in", "test.rs"),
            ("benches/bench.rs.in", "bench.rs"),
        ] {
            let src = Path::new(src);
            let dst = Path::new(&out_dir).join(dst);

            serde_codegen::expand(&src, &dst).unwrap();
            indoc::expand(&dst, &dst).unwrap();
        }
    }
}

#[cfg(not(feature = "with-syntex"))]
mod with_syntex {
    pub fn main() {}
}

pub fn main() {
    with_syntex::main();

    skeptic::generate_doc_tests(&["../README.md"]);
}
<|endoftext|>


<commit_before>use super::*;

/// A pending log reservation which can be aborted or completed.
/// NB the holder should quickly call `complete` or `abort` as
/// taking too long to decide will cause the underlying IO
/// buffer to become blocked.
pub struct Reservation<'a> {
    pub(super) log: &'a Log,
    pub(super) idx: usize,
    pub(super) header_buf: &'a mut [u8],
    pub(super) partial_checksum: Option<crc32fast::Hasher>,
    pub(super) flushed: bool,
    pub(super) ptr: DiskPtr,
    pub(super) lsn: Lsn,
    pub(super) is_blob_rewrite: bool,
}

impl<'a> Drop for Reservation<'a> {
    fn drop(&mut self) {
        // We auto-abort if the user never uses a reservation.
        if !self.flushed {
            self.flush(false).unwrap();
        }
    }
}

impl<'a> Reservation<'a> {
    /// Cancel the reservation, placing a failed flush on disk, returning
    /// the (cancelled) log sequence number and file offset.
    pub fn abort(mut self) -> Result<(Lsn, DiskPtr), ()> {
        if self.ptr.is_blob() && !self.is_blob_rewrite {
            // we don't want to remove this blob if something
            // else may still be using it.

            trace!(
                "removing blob for aborted reservation at lsn {}",
                self.ptr
            );

            remove_blob(self.ptr.blob().1, &self.log.config)?;
        }

        self.flush(false)
    }

    /// Complete the reservation, placing the buffer on disk. returns
    /// the log sequence number of the write, and the file offset.
    pub fn complete(mut self) -> Result<(Lsn, DiskPtr)> {
        self.flush(true)
    }

    /// Get the log file offset for reading this buffer in the future.
    pub fn lid(&self) -> LogId {
        self.ptr.lid()
    }

    /// Get the log sequence number for this update.
    pub fn lsn(&self) -> Lsn {
        self.lsn
    }

    /// Get the underlying storage location for the written value.
    /// Note that an blob write still has a pointer in the
    /// log at the provided lid location.
    pub fn ptr(&self) -> DiskPtr {
        self.ptr
    }

    fn flush(&mut self, valid: bool) -> Result<(Lsn, DiskPtr)> {
        if self.flushed {
            panic!("flushing already-flushed reservation!");
        }

        self.flushed = true;

        if !valid {
            // don't actually zero the message, still check its hash
            // on recovery to find corruption.
            self.header_buf[0] = FAILED_FLUSH;
        }

        let mut hasher = self.partial_checksum.take().unwrap();
        hasher.update(self.header_buf);
        let crc32 = hasher.finalize();
        let crc32_arr = u32_to_arr(crc32 ^ 0xFFFF_FFFF);

        unsafe {
            std::ptr::copy_nonoverlapping(
                crc32_arr.as_ptr(),
                self.header_buf.as_mut_ptr().offset(13),
                std::mem::size_of::<u32>(),
            );
        }
        self.log.exit_reservation(self.idx)?;

        Ok((self.lsn(), self.ptr()))
    }
}
<commit_msg>Fix bad automerge<commit_after>use super::*;

/// A pending log reservation which can be aborted or completed.
/// NB the holder should quickly call `complete` or `abort` as
/// taking too long to decide will cause the underlying IO
/// buffer to become blocked.
pub struct Reservation<'a> {
    pub(super) log: &'a Log,
    pub(super) idx: usize,
    pub(super) header_buf: &'a mut [u8],
    pub(super) partial_checksum: Option<crc32fast::Hasher>,
    pub(super) flushed: bool,
    pub(super) ptr: DiskPtr,
    pub(super) lsn: Lsn,
    pub(super) is_blob_rewrite: bool,
}

impl<'a> Drop for Reservation<'a> {
    fn drop(&mut self) {
        // We auto-abort if the user never uses a reservation.
        if !self.flushed {
            self.flush(false).unwrap();
        }
    }
}

impl<'a> Reservation<'a> {
    /// Cancel the reservation, placing a failed flush on disk, returning
    /// the (cancelled) log sequence number and file offset.
    pub fn abort(mut self) -> Result<(Lsn, DiskPtr)> {
        if self.ptr.is_blob() && !self.is_blob_rewrite {
            // we don't want to remove this blob if something
            // else may still be using it.

            trace!(
                "removing blob for aborted reservation at lsn {}",
                self.ptr
            );

            remove_blob(self.ptr.blob().1, &self.log.config)?;
        }

        self.flush(false)
    }

    /// Complete the reservation, placing the buffer on disk. returns
    /// the log sequence number of the write, and the file offset.
    pub fn complete(mut self) -> Result<(Lsn, DiskPtr)> {
        self.flush(true)
    }

    /// Get the log file offset for reading this buffer in the future.
    pub fn lid(&self) -> LogId {
        self.ptr.lid()
    }

    /// Get the log sequence number for this update.
    pub fn lsn(&self) -> Lsn {
        self.lsn
    }

    /// Get the underlying storage location for the written value.
    /// Note that an blob write still has a pointer in the
    /// log at the provided lid location.
    pub fn ptr(&self) -> DiskPtr {
        self.ptr
    }

    fn flush(&mut self, valid: bool) -> Result<(Lsn, DiskPtr)> {
        if self.flushed {
            panic!("flushing already-flushed reservation!");
        }

        self.flushed = true;

        if !valid {
            // don't actually zero the message, still check its hash
            // on recovery to find corruption.
            self.header_buf[0] = FAILED_FLUSH;
        }

        let mut hasher = self.partial_checksum.take().unwrap();
        hasher.update(self.header_buf);
        let crc32 = hasher.finalize();
        let crc32_arr = u32_to_arr(crc32 ^ 0xFFFF_FFFF);

        unsafe {
            std::ptr::copy_nonoverlapping(
                crc32_arr.as_ptr(),
                self.header_buf.as_mut_ptr().offset(13),
                std::mem::size_of::<u32>(),
            );
        }
        self.log.exit_reservation(self.idx)?;

        Ok((self.lsn(), self.ptr()))
    }
}
<|endoftext|>


<commit_before>//! This module contains the functionality to convert from the wacky tcx data
//! structures into the THIR. The `builder` is generally ignorant of the tcx,
//! etc., and instead goes through the `Cx` for most of its work.

use crate::thir::arena::Arena;
use crate::thir::util::UserAnnotatedTyHelpers;
use crate::thir::*;

use rustc_ast as ast;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::Node;
use rustc_middle::middle::region;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::ty::{self, Ty, TyCtxt};

pub fn build_thir<'thir, 'tcx>(
    tcx: TyCtxt<'tcx>,
    owner_def: ty::WithOptConstParam<LocalDefId>,
    arena: &'thir Arena<'thir, 'tcx>,
    expr: &'tcx hir::Expr<'tcx>,
) -> &'thir Expr<'thir, 'tcx> {
    Cx::new(tcx, owner_def, &arena).mirror_expr(expr)
}

struct Cx<'thir, 'tcx> {
    tcx: TyCtxt<'tcx>,
    arena: &'thir Arena<'thir, 'tcx>,

    crate param_env: ty::ParamEnv<'tcx>,

    crate region_scope_tree: &'tcx region::ScopeTree,
    crate typeck_results: &'tcx ty::TypeckResults<'tcx>,

    /// The `DefId` of the owner of this body.
    body_owner: DefId,
}

impl<'thir, 'tcx> Cx<'thir, 'tcx> {
    fn new(
        tcx: TyCtxt<'tcx>,
        def: ty::WithOptConstParam<LocalDefId>,
        arena: &'thir Arena<'thir, 'tcx>,
    ) -> Cx<'thir, 'tcx> {
        let typeck_results = tcx.typeck_opt_const_arg(def);
        Cx {
            tcx,
            arena,
            param_env: tcx.param_env(def.did),
            region_scope_tree: tcx.region_scope_tree(def.did),
            typeck_results,
            body_owner: def.did.to_def_id(),
        }
    }

    crate fn const_eval_literal(
        &mut self,
        lit: &'tcx ast::LitKind,
        ty: Ty<'tcx>,
        sp: Span,
        neg: bool,
    ) -> &'tcx ty::Const<'tcx> {
        trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);

        match self.tcx.at(sp).lit_to_const(LitToConstInput { lit, ty, neg }) {
            Ok(c) => c,
            Err(LitToConstError::UnparseableFloat) => {
                // FIXME(#31407) this is only necessary because float parsing is buggy
                self.tcx.sess.span_err(sp, "could not evaluate float literal (see issue #31407)");
                // create a dummy value and continue compiling
                Const::from_bits(self.tcx, 0, self.param_env.and(ty))
            }
            Err(LitToConstError::Reported) => {
                // create a dummy value and continue compiling
                Const::from_bits(self.tcx, 0, self.param_env.and(ty))
            }
            Err(LitToConstError::TypeError) => bug!("const_eval_literal: had type error"),
        }
    }

    crate fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> {
        let p = match self.tcx.hir().get(p.hir_id) {
            Node::Pat(p) | Node::Binding(p) => p,
            node => bug!("pattern became {:?}", node),
        };
        Pat::from_hir(self.tcx, self.param_env, self.typeck_results(), p)
    }
}

impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'_, 'tcx> {
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.tcx
    }

    fn typeck_results(&self) -> &ty::TypeckResults<'tcx> {
        self.typeck_results
    }
}

mod block;
mod expr;
<commit_msg>Use the explicit error constant instead of fake dummies<commit_after>//! This module contains the functionality to convert from the wacky tcx data
//! structures into the THIR. The `builder` is generally ignorant of the tcx,
//! etc., and instead goes through the `Cx` for most of its work.

use crate::thir::arena::Arena;
use crate::thir::util::UserAnnotatedTyHelpers;
use crate::thir::*;

use rustc_ast as ast;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::Node;
use rustc_middle::middle::region;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::ty::{self, Ty, TyCtxt};

pub fn build_thir<'thir, 'tcx>(
    tcx: TyCtxt<'tcx>,
    owner_def: ty::WithOptConstParam<LocalDefId>,
    arena: &'thir Arena<'thir, 'tcx>,
    expr: &'tcx hir::Expr<'tcx>,
) -> &'thir Expr<'thir, 'tcx> {
    Cx::new(tcx, owner_def, &arena).mirror_expr(expr)
}

struct Cx<'thir, 'tcx> {
    tcx: TyCtxt<'tcx>,
    arena: &'thir Arena<'thir, 'tcx>,

    crate param_env: ty::ParamEnv<'tcx>,

    crate region_scope_tree: &'tcx region::ScopeTree,
    crate typeck_results: &'tcx ty::TypeckResults<'tcx>,

    /// The `DefId` of the owner of this body.
    body_owner: DefId,
}

impl<'thir, 'tcx> Cx<'thir, 'tcx> {
    fn new(
        tcx: TyCtxt<'tcx>,
        def: ty::WithOptConstParam<LocalDefId>,
        arena: &'thir Arena<'thir, 'tcx>,
    ) -> Cx<'thir, 'tcx> {
        let typeck_results = tcx.typeck_opt_const_arg(def);
        Cx {
            tcx,
            arena,
            param_env: tcx.param_env(def.did),
            region_scope_tree: tcx.region_scope_tree(def.did),
            typeck_results,
            body_owner: def.did.to_def_id(),
        }
    }

    crate fn const_eval_literal(
        &mut self,
        lit: &'tcx ast::LitKind,
        ty: Ty<'tcx>,
        sp: Span,
        neg: bool,
    ) -> &'tcx ty::Const<'tcx> {
        trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);

        match self.tcx.at(sp).lit_to_const(LitToConstInput { lit, ty, neg }) {
            Ok(c) => c,
            Err(LitToConstError::UnparseableFloat) => {
                // FIXME(#31407) this is only necessary because float parsing is buggy
                self.tcx.sess.span_err(sp, "could not evaluate float literal (see issue #31407)");
                // create a dummy value and continue compiling
                self.tcx.const_error(ty)
            }
            Err(LitToConstError::Reported) => {
                // create a dummy value and continue compiling
                self.tcx.const_error(ty)
            }
            Err(LitToConstError::TypeError) => bug!("const_eval_literal: had type error"),
        }
    }

    crate fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> {
        let p = match self.tcx.hir().get(p.hir_id) {
            Node::Pat(p) | Node::Binding(p) => p,
            node => bug!("pattern became {:?}", node),
        };
        Pat::from_hir(self.tcx, self.param_env, self.typeck_results(), p)
    }
}

impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'_, 'tcx> {
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.tcx
    }

    fn typeck_results(&self) -> &ty::TypeckResults<'tcx> {
        self.typeck_results
    }
}

mod block;
mod expr;
<|endoftext|>


<commit_before>extern crate sovrin;

#[macro_use]
extern crate lazy_static;

#[path = "utils/mod.rs"]
mod utils;

use sovrin::api::ErrorCode;
use sovrin::api::pool::{sovrin_create_pool_ledger_config, sovrin_open_pool_ledger};
#[path = "../src/utils/environment.rs"]
mod environment;
use environment::EnvironmentUtils;

use std::ptr::null;

use utils::callbacks::CallbacksHelpers;

use std::sync::mpsc::{channel};
use std::ffi::{CString};

#[test]
fn sovrin_create_pool_ledger_can_be_called() {
    let (sender, receiver) = channel();

    let cb = Box::new(move |err| {
        sender.send(err).unwrap();
    });

    let (command_handle, callback) = CallbacksHelpers::closure_to_create_pool_ledger_cb(cb);

    let pool_name = CString::new("test_open").unwrap();
    let pool_config = CString::new("{\"genesis_txn\": \"./test_open_src.txn\"}").unwrap();
    std::fs::File::create("./test_open_src.txn").unwrap();

    let err = sovrin_create_pool_ledger_config(command_handle,
                                               pool_name.as_ptr(),
                                               pool_config.as_ptr(),
                                               callback);

    assert_eq!(ErrorCode::Success, err);

    let err = receiver.recv().unwrap();
    std::fs::remove_file("./test_open_src.txn").unwrap();
    std::fs::remove_dir_all(EnvironmentUtils::pool_path("test_open")).unwrap();
    assert_eq!(ErrorCode::Success, err);
}

#[test]
fn sovrin_open_pool_ledger_can_be_called() {
    let (sender, receiver) = channel();
    let sender2 = sender.clone();

    let cb = Box::new(move |err, _| {
        sender.send(err).unwrap();
    });
    let cb2 = Box::new(move |err, _| {
        sender2.send(err).unwrap();
    });

    let (command_handle, callback) = CallbacksHelpers::closure_to_open_pool_ledger_cb(cb);

    let pool_name = CString::new("test1").unwrap();

    let err = sovrin_open_pool_ledger(command_handle,
                                      pool_name.as_ptr(),
                                      null(),
                                      callback);

    assert_eq!(ErrorCode::Success, err);
    let err = receiver.recv().unwrap();
    assert_eq!(ErrorCode::Success, err);

    //TODO separate test to check error after open the same pool multiply times
    let (command_handle, callback) = CallbacksHelpers::closure_to_open_pool_ledger_cb(cb2);
    let pool_name = CString::new("test1").unwrap();
    let err = sovrin_open_pool_ledger(command_handle,
                                      pool_name.as_ptr(),
                                      null(),
                                      callback);

    assert_eq!(ErrorCode::Success, err);
    let err = receiver.recv().unwrap();
    assert_eq!(ErrorCode::PoolLedgerInvalidPoolHandle, err);
}
<commit_msg>Update sovrin_open_pool_ledger integration test.<commit_after>extern crate sovrin;

#[macro_use]
extern crate lazy_static;

#[path = "utils/mod.rs"]
mod utils;

use sovrin::api::ErrorCode;
use sovrin::api::pool::{sovrin_create_pool_ledger_config, sovrin_open_pool_ledger};
#[path = "../src/utils/environment.rs"]
mod environment;
use environment::EnvironmentUtils;

use std::fs;

use std::ptr::null;

use utils::callbacks::CallbacksHelpers;

use std::sync::mpsc::{channel};
use std::ffi::{CString};

#[test]
fn sovrin_create_pool_ledger_can_be_called() {
    let (sender, receiver) = channel();

    let cb = Box::new(move |err| {
        sender.send(err).unwrap();
    });

    let (command_handle, callback) = CallbacksHelpers::closure_to_create_pool_ledger_cb(cb);

    let pool_name = CString::new("test_open").unwrap();
    let pool_config = CString::new("{\"genesis_txn\": \"./test_open_src.txn\"}").unwrap();
    std::fs::File::create("./test_open_src.txn").unwrap();

    let err = sovrin_create_pool_ledger_config(command_handle,
                                               pool_name.as_ptr(),
                                               pool_config.as_ptr(),
                                               callback);

    assert_eq!(ErrorCode::Success, err);

    let err = receiver.recv().unwrap();
    std::fs::remove_file("./test_open_src.txn").unwrap();
    std::fs::remove_dir_all(EnvironmentUtils::pool_path("test_open")).unwrap();
    assert_eq!(ErrorCode::Success, err);
}

#[test]
fn sovrin_open_pool_ledger_can_be_called() {
    let (sender, receiver) = channel();
    let sender2 = sender.clone();

    let cb = Box::new(move |err, _| {
        sender.send(err).unwrap();
    });
    let cb2 = Box::new(move |err, _| {
        sender2.send(err).unwrap();
    });

    let (command_handle, callback) = CallbacksHelpers::closure_to_open_pool_ledger_cb(cb);

    let pool_name: String = "test1".to_string();
    let c_pool_name = CString::new(pool_name.as_str()).unwrap();
    let mut path = environment::EnvironmentUtils::pool_path(pool_name.as_str());
    fs::create_dir_all(path.as_path()).unwrap();
    path.push(pool_name);
    path.set_extension("txn");
    fs::File::create(path.as_path()).unwrap();

    let err = sovrin_open_pool_ledger(command_handle,
                                      c_pool_name.as_ptr(),
                                      null(),
                                      callback);

    assert_eq!(ErrorCode::Success, err);
    let err = receiver.recv().unwrap();
    assert_eq!(ErrorCode::Success, err);

    //TODO separate test to check error after open the same pool multiply times
    let (command_handle, callback) = CallbacksHelpers::closure_to_open_pool_ledger_cb(cb2);
    let err = sovrin_open_pool_ledger(command_handle,
                                      c_pool_name.as_ptr(),
                                      null(),
                                      callback);

    assert_eq!(ErrorCode::Success, err);
    let err = receiver.recv().unwrap();
    assert_eq!(ErrorCode::PoolLedgerInvalidPoolHandle, err);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;
use std::sync;

use crate::error::Result;
use crate::parser;
use crate::parser::Language;
use crate::runtime;
use crate::runtime::PartialStore;
use crate::runtime::Renderable;

use super::PartialCompiler;
use super::PartialSource;

/// An lazily-caching compiler for `PartialSource`.
///
/// This would be useful in cases where:
/// - Most partial-templates aren't used
/// - Of the used partial-templates, they are generally used many times.
///
/// Note: partial-compilation error reporting is deferred to render-time so content can still be
/// generated even when the content is in an intermediate-state.
#[derive(Debug)]
pub struct LazyCompiler<S: PartialSource> {
    source: S,
}

impl<S> LazyCompiler<S>
where
    S: PartialSource,
{
    /// Create an on-demand compiler for `PartialSource`.
    pub fn new(source: S) -> Self {
        LazyCompiler { source }
    }
}

impl<S> LazyCompiler<S>
where
    S: PartialSource + Default,
{
    /// Create an empty compiler for `PartialSource`.
    pub fn empty() -> Self {
        Default::default()
    }
}

impl<S> Default for LazyCompiler<S>
where
    S: PartialSource + Default,
{
    fn default() -> Self {
        Self {
            source: Default::default(),
        }
    }
}

impl<S> ::std::ops::Deref for LazyCompiler<S>
where
    S: PartialSource,
{
    type Target = S;

    fn deref(&self) -> &S {
        &self.source
    }
}

impl<S> ::std::ops::DerefMut for LazyCompiler<S>
where
    S: PartialSource,
{
    fn deref_mut(&mut self) -> &mut S {
        &mut self.source
    }
}

impl<S> PartialCompiler for LazyCompiler<S>
where
    S: PartialSource + Send + Sync + 'static,
{
    fn compile(self, language: sync::Arc<Language>) -> Result<Box<dyn PartialStore + Send + Sync>> {
        let store = LazyStore {
            language,
            source: self.source,
            cache: sync::Mutex::new(Default::default()),
        };
        Ok(Box::new(store))
    }

    fn source(&self) -> &dyn PartialSource {
        &self.source
    }
}

struct LazyStore<S: PartialSource> {
    language: sync::Arc<Language>,
    source: S,
    cache: sync::Mutex<HashMap<String, Result<sync::Arc<dyn runtime::Renderable>>>>,
}

impl<S> LazyStore<S>
where
    S: PartialSource,
{
    fn try_get_or_create(&self, name: &str) -> Option<sync::Arc<dyn Renderable>> {
        let cache = self.cache.lock().expect("not to be poisoned and reused");
        if let Some(result) = cache.get(name) {
            result.as_ref().ok().cloned()
        } else {
            let s = self.source.try_get(name)?;
            let s = s.as_ref();
            let template = parser::parse(s, &self.language)
                .map(runtime::Template::new)
                .map(sync::Arc::new)
                .ok()?;
            Some(template)
        }
    }

    fn get_or_create(&self, name: &str) -> Result<sync::Arc<dyn Renderable>> {
        let cache = self.cache.lock().expect("not to be poisoned and reused");
        if let Some(result) = cache.get(name) {
            result.clone()
        } else {
            let s = self.source.get(name)?;
            let s = s.as_ref();
            let template = parser::parse(s, &self.language)
                .map(runtime::Template::new)
                .map(sync::Arc::new)?;
            Ok(template)
        }
    }
}

impl<S> PartialStore for LazyStore<S>
where
    S: PartialSource,
{
    fn contains(&self, name: &str) -> bool {
        self.source.contains(name)
    }

    fn names(&self) -> Vec<&str> {
        self.source.names()
    }

    fn try_get(&self, name: &str) -> Option<sync::Arc<dyn Renderable>> {
        self.try_get_or_create(name)
    }

    fn get(&self, name: &str) -> Result<sync::Arc<dyn Renderable>> {
        self.get_or_create(name)
    }
}

impl<S> fmt::Debug for LazyStore<S>
where
    S: PartialSource,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.source.fmt(f)
    }
}
<commit_msg>fix(liquid-lib): Make LazyStore cache parsed partials<commit_after>use std::collections::HashMap;
use std::fmt;
use std::sync;

use crate::error::Result;
use crate::parser;
use crate::parser::Language;
use crate::runtime;
use crate::runtime::PartialStore;
use crate::runtime::Renderable;

use super::PartialCompiler;
use super::PartialSource;

/// An lazily-caching compiler for `PartialSource`.
///
/// This would be useful in cases where:
/// - Most partial-templates aren't used
/// - Of the used partial-templates, they are generally used many times.
///
/// Note: partial-compilation error reporting is deferred to render-time so content can still be
/// generated even when the content is in an intermediate-state.
#[derive(Debug)]
pub struct LazyCompiler<S: PartialSource> {
    source: S,
}

impl<S> LazyCompiler<S>
where
    S: PartialSource,
{
    /// Create an on-demand compiler for `PartialSource`.
    pub fn new(source: S) -> Self {
        LazyCompiler { source }
    }
}

impl<S> LazyCompiler<S>
where
    S: PartialSource + Default,
{
    /// Create an empty compiler for `PartialSource`.
    pub fn empty() -> Self {
        Default::default()
    }
}

impl<S> Default for LazyCompiler<S>
where
    S: PartialSource + Default,
{
    fn default() -> Self {
        Self {
            source: Default::default(),
        }
    }
}

impl<S> ::std::ops::Deref for LazyCompiler<S>
where
    S: PartialSource,
{
    type Target = S;

    fn deref(&self) -> &S {
        &self.source
    }
}

impl<S> ::std::ops::DerefMut for LazyCompiler<S>
where
    S: PartialSource,
{
    fn deref_mut(&mut self) -> &mut S {
        &mut self.source
    }
}

impl<S> PartialCompiler for LazyCompiler<S>
where
    S: PartialSource + Send + Sync + 'static,
{
    fn compile(self, language: sync::Arc<Language>) -> Result<Box<dyn PartialStore + Send + Sync>> {
        let store = LazyStore {
            language,
            source: self.source,
            cache: sync::Mutex::new(Default::default()),
        };
        Ok(Box::new(store))
    }

    fn source(&self) -> &dyn PartialSource {
        &self.source
    }
}

struct LazyStore<S: PartialSource> {
    language: sync::Arc<Language>,
    source: S,
    cache: sync::Mutex<HashMap<String, Result<sync::Arc<dyn runtime::Renderable>>>>,
}

impl<S> LazyStore<S>
where
    S: PartialSource,
{
    fn try_get_or_create(&self, name: &str) -> Option<sync::Arc<dyn Renderable>> {
        let mut cache = self.cache.lock().expect("not to be poisoned and reused");
        if let Some(result) = cache.get(name) {
            result.as_ref().ok().cloned()
        } else {
            let s = self.source.try_get(name)?;
            let s = s.as_ref();
            let template = parser::parse(s, &self.language)
                .map(runtime::Template::new)
                .map(sync::Arc::new)
                .map(|t| t as sync::Arc<dyn Renderable>);
            cache.insert(name.to_string(), template.clone());
            template.ok()
        }
    }

    fn get_or_create(&self, name: &str) -> Result<sync::Arc<dyn Renderable>> {
        let mut cache = self.cache.lock().expect("not to be poisoned and reused");
        if let Some(result) = cache.get(name) {
            result.clone()
        } else {
            let s = self.source.get(name)?;
            let s = s.as_ref();
            let template = parser::parse(s, &self.language)
                .map(runtime::Template::new)
                .map(sync::Arc::new)
                .map(|t| t as sync::Arc<dyn Renderable>);
            cache.insert(name.to_string(), template.clone());
            template
        }
    }
}

impl<S> PartialStore for LazyStore<S>
where
    S: PartialSource,
{
    fn contains(&self, name: &str) -> bool {
        self.source.contains(name)
    }

    fn names(&self) -> Vec<&str> {
        self.source.names()
    }

    fn try_get(&self, name: &str) -> Option<sync::Arc<dyn Renderable>> {
        self.try_get_or_create(name)
    }

    fn get(&self, name: &str) -> Result<sync::Arc<dyn Renderable>> {
        self.get_or_create(name)
    }
}

impl<S> fmt::Debug for LazyStore<S>
where
    S: PartialSource,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.source.fmt(f)
    }
}

#[cfg(test)]
mod test {
    use crate::partials::lazy;
    use crate::runtime::PartialStore;
    use crate::{partials, Language};
    use std::{borrow, sync};

    #[derive(Default, Debug, Clone, Copy)]
    struct TestSource;

    impl partials::PartialSource for TestSource {
        fn contains(&self, _name: &str) -> bool {
            true
        }

        fn names(&self) -> Vec<&str> {
            vec![]
        }

        fn try_get<'a>(&'a self, name: &str) -> Option<borrow::Cow<'a, str>> {
            match name {
                "example.txt" => Some("Hello Liquid!".into()),
                _ => None,
            }
        }
    }

    #[test]
    fn test_store_caches_get() {
        let options = Language::empty();
        let store = lazy::LazyStore {
            language: sync::Arc::new(options),
            source: TestSource,
            cache: sync::Mutex::new(Default::default()),
        };

        assert!(
            !store.cache.lock().unwrap().contains_key("example.txt"),
            "The store cache should not contain the key yet."
        );

        // Look up the partial, causing it to be cached
        let _ = store.get("example.txt").unwrap();

        assert!(
            store.cache.lock().unwrap().contains_key("example.txt"),
            "The store cache should now contain the key."
        );
    }

    #[test]
    fn test_store_caches_try_get() {
        let options = Language::empty();
        let store = lazy::LazyStore {
            language: sync::Arc::new(options),
            source: TestSource,
            cache: sync::Mutex::new(Default::default()),
        };

        assert!(
            !store.cache.lock().unwrap().contains_key("example.txt"),
            "The store cache should not contain the key yet."
        );

        // Look up the partial, causing it to be cached.
        let _ = store.try_get("example.txt").unwrap();

        assert!(
            store.cache.lock().unwrap().contains_key("example.txt"),
            "The store cache should now contain the key."
        );
    }
}
<|endoftext|>


<commit_before>//! ARM C Language Extensions (ACLE)
//!
//! # Developer notes
//!
//! Below is a list of built-in targets that are representative of the different ARM
//! architectures; the list includes the `target_feature`s they possess.
//!
//! - `armv4t-unknown-linux-gnueabi` - **ARMv4** - `+v4t`
//! - `armv5te-unknown-linux-gnueabi` - **ARMv5TE** - `+v4t +v5te`
//! - `arm-unknown-linux-gnueabi` - **ARMv6** - `+v4t +v5te +v6`
//! - `thumbv6m-none-eabi` - **ARMv6-M** - `+v4t +v5te +v6 +thumb-mode +mclass`
//! - `armv7-unknown-linux-gnueabihf` - **ARMv7-A** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +aclass`
//! - `armv7r-none-eabi` - **ARMv7-R** - `+v4t +v5te +v6 +v6k +v6t2  +v7 +dsp +thumb2 +rclass`
//! - `thumbv7m-none-eabi` - **ARMv7-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +thumb2 +thumb-mode +mclass`
//! - `thumbv7em-none-eabi` - **ARMv7E-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +thumb-mode +mclass`
//! - `aarch64-unknown-linux-gnu` - **ARMv8-A (AArch64)** - `+fp +neon`
//!
//! Section 10.1 of ACLE says:
//!
//! - "In the sequence of Arm architectures { v5, v5TE, v6, v6T2, v7 } each architecture includes
//! its predecessor instruction set."
//!
//! - "In the sequence of Thumb-only architectures { v6-M, v7-M, v7E-M } each architecture includes
//! its predecessor instruction set."
//!
//! From that info and from looking at how LLVM features work (using custom targets) we can identify
//! features that are subsets of others:
//!
//! Legend: `a < b` reads as "`a` is a subset of `b`"; this means that if `b` is enabled then `a` is
//! enabled as well.
//!
//! - `v4t < v5te < v6 < v6k < v6t2 < v7 < v8`
//! - `v6 < v8m < v6t2`
//! - `v7 < v8m.main`
//!
//! # References
//!
//! - [ACLE Q2 2018](https://developer.arm.com/docs/101028/latest)

// 8, 7 and 6-M are supported via dedicated instructions like DMB. All other arches are supported
// via CP15 instructions. See Section 10.1 of ACLE
mod barrier;

#[cfg(any(
    target_arch = "aarch64",
    target_feature = "v7",
    target_feature = "mclass"
))]
pub use self::barrier::*;

mod hints;

pub use self::hints::*;

mod registers;

pub use self::registers::*;

// Supported arches: 5TE, 7E-M. See Section 10.1 of ACLE (e.g. QADD)
// We also include the A profile even though DSP is deprecated on that profile as of ACLE 2.0 (see
// section 5.4.7)
#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        // >= v5TE but excludes v7-A
        all(target_feature = "v5te", not(target_feature = "mclass")),
        // v7E-M
        all(target_feature = "mclass", target_feature = "dsp"),
    )
))]
mod dsp;

#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        all(target_feature = "v5te", not(target_feature = "mclass")),
        all(target_feature = "mclass", target_feature = "dsp"),
    )
))]
pub use self::dsp::*;

// Supported arches: 6, 7-M. See Section 10.1 of ACLE (e.g. SSAT)
#[cfg(all(
    not(target_arch = "aarch64"),
    target_feature = "v6",
))]
mod sat;

#[cfg(all(
    not(target_arch = "aarch64"),
    target_feature = "v6",
))]
pub use self::sat::*;

// Deprecated in ACLE 2.0 for the A profile but fully supported on the M and R profiles, says
// Section 5.4.9 of ACLE. We'll expose these for the A profile even if deprecated
#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        // v7-A, v7-R
        all(target_feature = "v6", not(target_feature = "mclass")),
        // v7E-M
        all(target_feature = "mclass", target_feature = "dsp")
    )
))]
mod simd32;

#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        all(target_feature = "v6", not(target_feature = "mclass")),
        all(target_feature = "mclass", target_feature = "dsp")
    )
))]
pub use self::simd32::*;

mod sealed {
    pub trait Dmb {
        unsafe fn __dmb(&self);
    }

    pub trait Dsb {
        unsafe fn __dsb(&self);
    }

    pub trait Isb {
        unsafe fn __isb(&self);
    }

    pub trait Rsr {
        unsafe fn __rsr(&self) -> u32;
    }

    pub trait Rsr64 {
        unsafe fn __rsr64(&self) -> u64;
    }

    pub trait Rsrp {
        unsafe fn __rsrp(&self) -> *const u8;
    }

    pub trait Wsr {
        unsafe fn __wsr(&self, value: u32);
    }

    pub trait Wsr64 {
        unsafe fn __wsr64(&self, value: u64);
    }

    pub trait Wsrp {
        unsafe fn __wsrp(&self, value: *const u8);
    }
}
<commit_msg>acle/barrier: remove cfg from re-export<commit_after>//! ARM C Language Extensions (ACLE)
//!
//! # Developer notes
//!
//! Below is a list of built-in targets that are representative of the different ARM
//! architectures; the list includes the `target_feature`s they possess.
//!
//! - `armv4t-unknown-linux-gnueabi` - **ARMv4** - `+v4t`
//! - `armv5te-unknown-linux-gnueabi` - **ARMv5TE** - `+v4t +v5te`
//! - `arm-unknown-linux-gnueabi` - **ARMv6** - `+v4t +v5te +v6`
//! - `thumbv6m-none-eabi` - **ARMv6-M** - `+v4t +v5te +v6 +thumb-mode +mclass`
//! - `armv7-unknown-linux-gnueabihf` - **ARMv7-A** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +aclass`
//! - `armv7r-none-eabi` - **ARMv7-R** - `+v4t +v5te +v6 +v6k +v6t2  +v7 +dsp +thumb2 +rclass`
//! - `thumbv7m-none-eabi` - **ARMv7-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +thumb2 +thumb-mode +mclass`
//! - `thumbv7em-none-eabi` - **ARMv7E-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +thumb-mode +mclass`
//! - `aarch64-unknown-linux-gnu` - **ARMv8-A (AArch64)** - `+fp +neon`
//!
//! Section 10.1 of ACLE says:
//!
//! - "In the sequence of Arm architectures { v5, v5TE, v6, v6T2, v7 } each architecture includes
//! its predecessor instruction set."
//!
//! - "In the sequence of Thumb-only architectures { v6-M, v7-M, v7E-M } each architecture includes
//! its predecessor instruction set."
//!
//! From that info and from looking at how LLVM features work (using custom targets) we can identify
//! features that are subsets of others:
//!
//! Legend: `a < b` reads as "`a` is a subset of `b`"; this means that if `b` is enabled then `a` is
//! enabled as well.
//!
//! - `v4t < v5te < v6 < v6k < v6t2 < v7 < v8`
//! - `v6 < v8m < v6t2`
//! - `v7 < v8m.main`
//!
//! # References
//!
//! - [ACLE Q2 2018](https://developer.arm.com/docs/101028/latest)

// 8, 7 and 6-M are supported via dedicated instructions like DMB. All other arches are supported
// via CP15 instructions. See Section 10.1 of ACLE
mod barrier;

pub use self::barrier::*;

mod hints;

pub use self::hints::*;

mod registers;

pub use self::registers::*;

// Supported arches: 5TE, 7E-M. See Section 10.1 of ACLE (e.g. QADD)
// We also include the A profile even though DSP is deprecated on that profile as of ACLE 2.0 (see
// section 5.4.7)
#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        // >= v5TE but excludes v7-A
        all(target_feature = "v5te", not(target_feature = "mclass")),
        // v7E-M
        all(target_feature = "mclass", target_feature = "dsp"),
    )
))]
mod dsp;

#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        all(target_feature = "v5te", not(target_feature = "mclass")),
        all(target_feature = "mclass", target_feature = "dsp"),
    )
))]
pub use self::dsp::*;

// Supported arches: 6, 7-M. See Section 10.1 of ACLE (e.g. SSAT)
#[cfg(all(
    not(target_arch = "aarch64"),
    target_feature = "v6",
))]
mod sat;

#[cfg(all(
    not(target_arch = "aarch64"),
    target_feature = "v6",
))]
pub use self::sat::*;

// Deprecated in ACLE 2.0 for the A profile but fully supported on the M and R profiles, says
// Section 5.4.9 of ACLE. We'll expose these for the A profile even if deprecated
#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        // v7-A, v7-R
        all(target_feature = "v6", not(target_feature = "mclass")),
        // v7E-M
        all(target_feature = "mclass", target_feature = "dsp")
    )
))]
mod simd32;

#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        all(target_feature = "v6", not(target_feature = "mclass")),
        all(target_feature = "mclass", target_feature = "dsp")
    )
))]
pub use self::simd32::*;

mod sealed {
    pub trait Dmb {
        unsafe fn __dmb(&self);
    }

    pub trait Dsb {
        unsafe fn __dsb(&self);
    }

    pub trait Isb {
        unsafe fn __isb(&self);
    }

    pub trait Rsr {
        unsafe fn __rsr(&self) -> u32;
    }

    pub trait Rsr64 {
        unsafe fn __rsr64(&self) -> u64;
    }

    pub trait Rsrp {
        unsafe fn __rsrp(&self) -> *const u8;
    }

    pub trait Wsr {
        unsafe fn __wsr(&self, value: u32);
    }

    pub trait Wsr64 {
        unsafe fn __wsr64(&self, value: u64);
    }

    pub trait Wsrp {
        unsafe fn __wsrp(&self, value: *const u8);
    }
}
<|endoftext|>