<commit_before>use na::{self, Real};

use utils;
use shape::Triangle;
use query::{PointProjection, PointQuery, PointQueryWithLocation};
use math::{Isometry, Point};

#[inline]
fn compute_result<P: Point>(pt: &P, proj: P) -> PointProjection<P> {
    if na::dimension::<P::Vector>() == 2 {
        PointProjection::new(*pt == proj, proj)
    } else {
        // FIXME: is this acceptable to assume the point is inside of the triangle if it is close
        // enough?
        PointProjection::new(relative_eq!(proj, *pt), proj)
    }
}

impl<P: Point, M: Isometry<P>> PointQuery<P, M> for Triangle<P> {
    #[inline]
    fn project_point(&self, m: &M, pt: &P, solid: bool) -> PointProjection<P> {
        let (projection, _) = self.project_point_with_location(m, pt, solid);
        projection
    }

    // NOTE: the default implementation of `.distance_to_point(...)` will return the error that was
    // eaten by the `::approx_eq(...)` on `project_point(...)`.
}

/// Logical description of the location of a point on a triangle.
#[derive(Copy, Clone, Debug)]
pub enum TrianglePointLocation<N: Real> {
    /// The point lies on a vertex.
    OnVertex(usize),
    /// The point lies on an edge.
    OnEdge(usize, [N; 2]),
    /// The point lies on the triangle interior.
    OnFace([N; 3]),
    /// The point lies on the triangle interior (for "solid" point queries).
    OnSolid,
}

impl<N: Real> TrianglePointLocation<N> {
    /// Returns `true` if the point is located on the relative interior of the triangle.
    pub fn is_on_face(&self) -> bool {
        if let TrianglePointLocation::OnFace(_) = *self {
            true
        } else {
            false
        }
    }
}

impl<P: Point, M: Isometry<P>> PointQueryWithLocation<P, M> for Triangle<P> {
    type Location = TrianglePointLocation<P::Real>;

    #[inline]
    fn project_point_with_location(
        &self,
        m: &M,
        pt: &P,
        solid: bool,
    ) -> (PointProjection<P>, Self::Location) {
        let a = *self.a();
        let b = *self.b();
        let c = *self.c();
        let p = m.inverse_transform_point(pt);

        let _1 = na::one::<P::Real>();

        let ab = b - a;
        let ac = c - a;
        let ap = p - a;

        let ab_ap = na::dot(&ab, &ap);
        let ac_ap = na::dot(&ac, &ap);

        if ab_ap <= na::zero() && ac_ap <= na::zero() {
            // Voronoï region of `a`.
            return (
                compute_result(pt, m.transform_point(&a)),
                TrianglePointLocation::OnVertex(0),
            );
        }

        let bp = p - b;
        let ab_bp = na::dot(&ab, &bp);
        let ac_bp = na::dot(&ac, &bp);

        if ab_bp >= na::zero() && ac_bp <= ab_bp {
            // Voronoï region of `b`.
            return (
                compute_result(pt, m.transform_point(&b)),
                TrianglePointLocation::OnVertex(1),
            );
        }

        let cp = p - c;
        let ab_cp = na::dot(&ab, &cp);
        let ac_cp = na::dot(&ac, &cp);

        if ac_cp >= na::zero() && ab_cp <= ac_cp {
            // Voronoï region of `c`.
            return (
                compute_result(pt, m.transform_point(&c)),
                TrianglePointLocation::OnVertex(2),
            );
        }

        enum ProjectionInfo<N> {
            OnAB,
            OnAC,
            OnBC,
            OnFace(N, N, N)
        }

        // Checks on which edge voronoï region the point is.
        // For 2D and 3D, it uses explicit cross/perp products that are
        // more numerically stable.
        fn stable_check_edges_voronoi<P: Point>(ab: &P::Vector, ac: &P::Vector, bc: &P::Vector,
                                                ap: &P::Vector, bp: &P::Vector, cp: &P::Vector,
                                                ab_ap: P::Real, ab_bp: P::Real,
                                                ac_ap: P::Real, ac_cp: P::Real,
                                                ac_bp: P::Real, ab_cp: P::Real)
                                               -> ProjectionInfo<P::Real> {
            match na::dimension::<P::Vector>() {
                2 => {
                    let n = utils::perp2(ab, ac);
                    let vc = n * utils::perp2(ab, ap);
                    if vc < na::zero() && ab_ap >= na::zero() && ab_bp <= na::zero() {
                        return ProjectionInfo::OnAB;
                    }

                    let vb = -n * utils::perp2(ac, cp);
                    if vb < na::zero() && ac_ap >= na::zero() && ac_cp <= na::zero() {
                        return ProjectionInfo::OnAC;
                    }

                    let va = n * utils::perp2(bc, bp);
                    if  va < na::zero() && ac_bp - ab_bp >= na::zero() && ab_cp - ac_cp >= na::zero() {
                        return ProjectionInfo::OnBC;
                    }

                    return ProjectionInfo::OnFace(va, vb, vc);
                },
                3 => {
                    let n = utils::cross3(ab, ac);
                    let vc = na::dot(&n, &utils::cross3(ab, ap));
                    if vc < na::zero() && ab_ap >= na::zero() && ab_bp <= na::zero() {
                        return ProjectionInfo::OnAB;
                    }

                    let vb = -na::dot(&n, &utils::cross3(ac, cp));
                    if vb < na::zero() && ac_ap >= na::zero() && ac_cp <= na::zero() {
                        return ProjectionInfo::OnAC;
                    }

                    let va = na::dot(&n, &utils::cross3(bc, bp));
                    if  va < na::zero() && ac_bp - ab_bp >= na::zero() && ab_cp - ac_cp >= na::zero() {
                        return ProjectionInfo::OnBC;
                    }

                    return ProjectionInfo::OnFace(va, vb, vc);
                },
                _ => {
                    // Generic version for other dimension. May suffer from severe catastrophic cancellation issues.
                    let vc = ab_ap * ac_bp - ab_bp * ac_ap;
                    if vc < na::zero() && ab_ap >= na::zero() && ab_bp <= na::zero() {
                        return ProjectionInfo::OnAB;
                    }

                    let vb = ab_cp * ac_ap - ab_ap * ac_cp;
                    if vb < na::zero() && ac_ap >= na::zero() && ac_cp <= na::zero() {
                        return ProjectionInfo::OnAC;
                    }

                    let va = ab_bp * ac_cp - ab_cp * ac_bp;
                    if  va < na::zero() && ac_bp - ab_bp >= na::zero() && ab_cp - ac_cp >= na::zero() {
                        return ProjectionInfo::OnBC;
                    }

                    return ProjectionInfo::OnFace(va, vb, vc);
                }
            }
        }

        let bc = c - b;
        match stable_check_edges_voronoi::<P>(&ab, &ac, &bc,
                                              &ap, &bp, &cp,
                                              ab_ap, ab_bp,
                                              ac_ap, ac_cp,
                                              ac_bp, ab_cp) {
            ProjectionInfo::OnAB => {
                // Voronoï region of `ab`.
                let v = ab_ap / na::norm_squared(&ab);
                let bcoords = [_1 - v, v];

                let mut res = a;
                // NOTE: we use axpy for the GJK AnnotatedPoint trick.
                res.axpy(bcoords[1], &b, bcoords[0]);
                return (
                    compute_result(pt, m.transform_point(&res)),
                    TrianglePointLocation::OnEdge(0, bcoords),
                );
            },
            ProjectionInfo::OnAC => {
                // Voronoï region of `ac`.
                let w = ac_ap / na::norm_squared(&ac);
                let bcoords = [_1 - w, w];

                let mut res = a;
                res.axpy(bcoords[1], &c, bcoords[0]);
                return (
                    compute_result(pt, m.transform_point(&res)),
                    TrianglePointLocation::OnEdge(2, bcoords),
                );
            },
            ProjectionInfo::OnBC => {
                // Voronoï region of `bc`.
                let bc = c - b;
                let w = na::dot(&bc, &ap) / na::norm_squared(&bc);
                let bcoords = [_1 - w, w];

                let mut res = b;
                res.axpy(bcoords[1], &c, bcoords[0]);
                return (
                    compute_result(pt, m.transform_point(&res)),
                    TrianglePointLocation::OnEdge(1, bcoords),
                );
            },
            ProjectionInfo::OnFace(va, vb, vc) => {
                // Voronoï region of the face.
                if na::dimension::<P::Vector>() != 2 {
                    let denom = _1 / (va + vb + vc);
                    let v = vb * denom;
                    let w = vc * denom;
                    let bcoords = [_1 - v - w, v, w];

                    let mut res = a;
                    res.axpy(bcoords[1], &b, bcoords[0]);
                    res.axpy(bcoords[2], &c, _1);

                    return (
                        compute_result(pt, m.transform_point(&res)),
                        TrianglePointLocation::OnFace(bcoords),
                    );
                }
            }
        }

        // Special treatement if we work in 2d because in this case we really are inside of the
        // object.
        if solid {
            (
                PointProjection::new(true, *pt),
                TrianglePointLocation::OnSolid,
            )
        } else {
            // We have to project on the closest edge.

            // FIXME: this might be optimizable.
            let v = ab_ap /  (ab_ap - ab_bp); // proj on ab = a + ab * v
            let w = ac_ap / (ac_ap - ac_cp); // proj on ac = a + ac * w
            let u = (ac_bp - ab_bp) / (ac_bp - ab_bp +  ab_cp - ac_cp); // proj on bc = b + bc * u

            let bc = c - b;
            let d_ab = na::norm_squared(&ap) - (na::norm_squared(&ab) * v * v);
            let d_ac = na::norm_squared(&ap) - (na::norm_squared(&ac) * u * u);
            let d_bc = na::norm_squared(&bp) - (na::norm_squared(&bc) * w * w);

            let mut proj;
            let loc;

            if d_ab < d_ac {
                if d_ab < d_bc {
                    // ab
                    let bcoords = [_1 - v, v];
                    proj = a;
                    proj.axpy(bcoords[1], &b, bcoords[0]);
                    proj = m.transform_point(&proj);
                    loc = TrianglePointLocation::OnEdge(0, bcoords);
                } else {
                    // bc
                    let bcoords = [_1 - u, u];
                    proj = b;
                    proj.axpy(bcoords[1], &c, bcoords[0]);
                    proj = m.transform_point(&proj);
                    loc = TrianglePointLocation::OnEdge(1, bcoords);
                }
            } else {
                if d_ac < d_bc {
                    // ac
                    let bcoords = [_1 - w, w];
                    proj = a;
                    proj.axpy(bcoords[1], &c, bcoords[0]);
                    proj = m.transform_point(&proj);
                    loc = TrianglePointLocation::OnEdge(2, bcoords);
                } else {
                    // bc
                    let bcoords = [_1 - u, u];
                    proj = b;
                    proj.axpy(bcoords[1], &c, bcoords[0]);
                    proj = m.transform_point(&proj);
                    loc = TrianglePointLocation::OnEdge(1, bcoords);
                }
            }

            (PointProjection::new(true, proj), loc)
        }
    }
}
<commit_msg>Fix bug in point-triangle projection.<commit_after>use na::{self, Real};

use utils;
use shape::Triangle;
use query::{PointProjection, PointQuery, PointQueryWithLocation};
use math::{Isometry, Point};

#[inline]
fn compute_result<P: Point>(pt: &P, proj: P) -> PointProjection<P> {
    if na::dimension::<P::Vector>() == 2 {
        PointProjection::new(*pt == proj, proj)
    } else {
        // FIXME: is this acceptable to assume the point is inside of the triangle if it is close
        // enough?
        PointProjection::new(relative_eq!(proj, *pt), proj)
    }
}

impl<P: Point, M: Isometry<P>> PointQuery<P, M> for Triangle<P> {
    #[inline]
    fn project_point(&self, m: &M, pt: &P, solid: bool) -> PointProjection<P> {
        let (projection, _) = self.project_point_with_location(m, pt, solid);
        projection
    }

    // NOTE: the default implementation of `.distance_to_point(...)` will return the error that was
    // eaten by the `::approx_eq(...)` on `project_point(...)`.
}

/// Logical description of the location of a point on a triangle.
#[derive(Copy, Clone, Debug)]
pub enum TrianglePointLocation<N: Real> {
    /// The point lies on a vertex.
    OnVertex(usize),
    /// The point lies on an edge.
    OnEdge(usize, [N; 2]),
    /// The point lies on the triangle interior.
    OnFace([N; 3]),
    /// The point lies on the triangle interior (for "solid" point queries).
    OnSolid,
}

impl<N: Real> TrianglePointLocation<N> {
    /// Returns `true` if the point is located on the relative interior of the triangle.
    pub fn is_on_face(&self) -> bool {
        if let TrianglePointLocation::OnFace(_) = *self {
            true
        } else {
            false
        }
    }
}

impl<P: Point, M: Isometry<P>> PointQueryWithLocation<P, M> for Triangle<P> {
    type Location = TrianglePointLocation<P::Real>;

    #[inline]
    fn project_point_with_location(
        &self,
        m: &M,
        pt: &P,
        solid: bool,
    ) -> (PointProjection<P>, Self::Location) {
        let a = *self.a();
        let b = *self.b();
        let c = *self.c();
        let p = m.inverse_transform_point(pt);

        let _1 = na::one::<P::Real>();

        let ab = b - a;
        let ac = c - a;
        let ap = p - a;

        let ab_ap = na::dot(&ab, &ap);
        let ac_ap = na::dot(&ac, &ap);

        if ab_ap <= na::zero() && ac_ap <= na::zero() {
            // Voronoï region of `a`.
            return (
                compute_result(pt, m.transform_point(&a)),
                TrianglePointLocation::OnVertex(0),
            );
        }

        let bp = p - b;
        let ab_bp = na::dot(&ab, &bp);
        let ac_bp = na::dot(&ac, &bp);

        if ab_bp >= na::zero() && ac_bp <= ab_bp {
            // Voronoï region of `b`.
            return (
                compute_result(pt, m.transform_point(&b)),
                TrianglePointLocation::OnVertex(1),
            );
        }

        let cp = p - c;
        let ab_cp = na::dot(&ab, &cp);
        let ac_cp = na::dot(&ac, &cp);

        if ac_cp >= na::zero() && ab_cp <= ac_cp {
            // Voronoï region of `c`.
            return (
                compute_result(pt, m.transform_point(&c)),
                TrianglePointLocation::OnVertex(2),
            );
        }

        enum ProjectionInfo<N> {
            OnAB,
            OnAC,
            OnBC,
            OnFace(N, N, N),
        }

        // Checks on which edge voronoï region the point is.
        // For 2D and 3D, it uses explicit cross/perp products that are
        // more numerically stable.
        fn stable_check_edges_voronoi<P: Point>(
            ab: &P::Vector,
            ac: &P::Vector,
            bc: &P::Vector,
            ap: &P::Vector,
            bp: &P::Vector,
            cp: &P::Vector,
            ab_ap: P::Real,
            ab_bp: P::Real,
            ac_ap: P::Real,
            ac_cp: P::Real,
            ac_bp: P::Real,
            ab_cp: P::Real,
        ) -> ProjectionInfo<P::Real> {
            match na::dimension::<P::Vector>() {
                2 => {
                    let n = utils::perp2(ab, ac);
                    let vc = n * utils::perp2(ab, ap);
                    if vc < na::zero() && ab_ap >= na::zero() && ab_bp <= na::zero() {
                        return ProjectionInfo::OnAB;
                    }

                    let vb = -n * utils::perp2(ac, cp);
                    if vb < na::zero() && ac_ap >= na::zero() && ac_cp <= na::zero() {
                        return ProjectionInfo::OnAC;
                    }

                    let va = n * utils::perp2(bc, bp);
                    if va < na::zero() && ac_bp - ab_bp >= na::zero() && ab_cp - ac_cp >= na::zero()
                    {
                        return ProjectionInfo::OnBC;
                    }

                    return ProjectionInfo::OnFace(va, vb, vc);
                }
                3 => {
                    let n = utils::cross3(ab, ac);
                    let vc = na::dot(&n, &utils::cross3(ab, ap));
                    if vc < na::zero() && ab_ap >= na::zero() && ab_bp <= na::zero() {
                        return ProjectionInfo::OnAB;
                    }

                    let vb = -na::dot(&n, &utils::cross3(ac, cp));
                    if vb < na::zero() && ac_ap >= na::zero() && ac_cp <= na::zero() {
                        return ProjectionInfo::OnAC;
                    }

                    let va = na::dot(&n, &utils::cross3(bc, bp));
                    if va < na::zero() && ac_bp - ab_bp >= na::zero() && ab_cp - ac_cp >= na::zero()
                    {
                        return ProjectionInfo::OnBC;
                    }

                    return ProjectionInfo::OnFace(va, vb, vc);
                }
                _ => {
                    // Generic version for other dimension. May suffer from severe catastrophic cancellation issues.
                    let vc = ab_ap * ac_bp - ab_bp * ac_ap;
                    if vc < na::zero() && ab_ap >= na::zero() && ab_bp <= na::zero() {
                        return ProjectionInfo::OnAB;
                    }

                    let vb = ab_cp * ac_ap - ab_ap * ac_cp;
                    if vb < na::zero() && ac_ap >= na::zero() && ac_cp <= na::zero() {
                        return ProjectionInfo::OnAC;
                    }

                    let va = ab_bp * ac_cp - ab_cp * ac_bp;
                    if va < na::zero() && ac_bp - ab_bp >= na::zero() && ab_cp - ac_cp >= na::zero()
                    {
                        return ProjectionInfo::OnBC;
                    }

                    return ProjectionInfo::OnFace(va, vb, vc);
                }
            }
        }

        let bc = c - b;
        match stable_check_edges_voronoi::<P>(
            &ab,
            &ac,
            &bc,
            &ap,
            &bp,
            &cp,
            ab_ap,
            ab_bp,
            ac_ap,
            ac_cp,
            ac_bp,
            ab_cp,
        ) {
            ProjectionInfo::OnAB => {
                // Voronoï region of `ab`.
                let v = ab_ap / na::norm_squared(&ab);
                let bcoords = [_1 - v, v];

                let mut res = a;
                // NOTE: we use axpy for the GJK AnnotatedPoint trick.
                res.axpy(bcoords[1], &b, bcoords[0]);
                return (
                    compute_result(pt, m.transform_point(&res)),
                    TrianglePointLocation::OnEdge(0, bcoords),
                );
            }
            ProjectionInfo::OnAC => {
                // Voronoï region of `ac`.
                let w = ac_ap / na::norm_squared(&ac);
                let bcoords = [_1 - w, w];

                let mut res = a;
                res.axpy(bcoords[1], &c, bcoords[0]);
                return (
                    compute_result(pt, m.transform_point(&res)),
                    TrianglePointLocation::OnEdge(2, bcoords),
                );
            }
            ProjectionInfo::OnBC => {
                // Voronoï region of `bc`.
                let w = na::dot(&bc, &bp) / na::norm_squared(&bc);
                let bcoords = [_1 - w, w];

                let mut res = b;
                res.axpy(bcoords[1], &c, bcoords[0]);
                return (
                    compute_result(pt, m.transform_point(&res)),
                    TrianglePointLocation::OnEdge(1, bcoords),
                );
            }
            ProjectionInfo::OnFace(va, vb, vc) => {
                // Voronoï region of the face.
                if na::dimension::<P::Vector>() != 2 {
                    let denom = _1 / (va + vb + vc);
                    let v = vb * denom;
                    let w = vc * denom;
                    let bcoords = [_1 - v - w, v, w];

                    let mut res = a;
                    res.axpy(bcoords[1], &b, bcoords[0]);
                    res.axpy(bcoords[2], &c, _1);

                    return (
                        compute_result(pt, m.transform_point(&res)),
                        TrianglePointLocation::OnFace(bcoords),
                    );
                }
            }
        }

        // Special treatement if we work in 2d because in this case we really are inside of the
        // object.
        if solid {
            (
                PointProjection::new(true, *pt),
                TrianglePointLocation::OnSolid,
            )
        } else {
            // We have to project on the closest edge.

            // FIXME: this might be optimizable.
            let v = ab_ap / (ab_ap - ab_bp); // proj on ab = a + ab * v
            let w = ac_ap / (ac_ap - ac_cp); // proj on ac = a + ac * w
            let u = (ac_bp - ab_bp) / (ac_bp - ab_bp + ab_cp - ac_cp); // proj on bc = b + bc * u

            let bc = c - b;
            let d_ab = na::norm_squared(&ap) - (na::norm_squared(&ab) * v * v);
            let d_ac = na::norm_squared(&ap) - (na::norm_squared(&ac) * u * u);
            let d_bc = na::norm_squared(&bp) - (na::norm_squared(&bc) * w * w);

            let mut proj;
            let loc;

            if d_ab < d_ac {
                if d_ab < d_bc {
                    // ab
                    let bcoords = [_1 - v, v];
                    proj = a;
                    proj.axpy(bcoords[1], &b, bcoords[0]);
                    proj = m.transform_point(&proj);
                    loc = TrianglePointLocation::OnEdge(0, bcoords);
                } else {
                    // bc
                    let bcoords = [_1 - u, u];
                    proj = b;
                    proj.axpy(bcoords[1], &c, bcoords[0]);
                    proj = m.transform_point(&proj);
                    loc = TrianglePointLocation::OnEdge(1, bcoords);
                }
            } else {
                if d_ac < d_bc {
                    // ac
                    let bcoords = [_1 - w, w];
                    proj = a;
                    proj.axpy(bcoords[1], &c, bcoords[0]);
                    proj = m.transform_point(&proj);
                    loc = TrianglePointLocation::OnEdge(2, bcoords);
                } else {
                    // bc
                    let bcoords = [_1 - u, u];
                    proj = b;
                    proj.axpy(bcoords[1], &c, bcoords[0]);
                    proj = m.transform_point(&proj);
                    loc = TrianglePointLocation::OnEdge(1, bcoords);
                }
            }

            (PointProjection::new(true, proj), loc)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use super::*;

use kvm_bindings::KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
use kvm_ioctls::CpuId;

use bit_helper::BitHelper;
use cpu_leaf::*;
use transformer::common::use_host_cpuid_function;

pub fn update_structured_extended_entry(
    entry: &mut kvm_cpuid_entry2,
    _vm_spec: &VmSpec,
) -> Result<(), Error> {
    use cpu_leaf::leaf_0x7::index0::*;

    // KVM sets this bit no matter what but this feature is not supported by hardware
    entry.edx.write_bit(edx::ARCH_CAPABILITIES_BITINDEX, false);

    Ok(())
}

pub fn update_extended_cache_topology_entry(
    entry: &mut kvm_cpuid_entry2,
    vm_spec: &VmSpec,
) -> Result<(), Error> {
    entry.flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;

    common::update_cache_parameters_entry(entry, vm_spec)
}

pub struct AmdCpuidTransformer {}

impl CpuidTransformer for AmdCpuidTransformer {
    fn preprocess_cpuid(&self, cpuid: &mut CpuId) -> Result<(), Error> {
        use_host_cpuid_function(cpuid, leaf_0x8000001d::LEAF_NUM)
    }

    fn transform_entry(&self, entry: &mut kvm_cpuid_entry2, vm_spec: &VmSpec) -> Result<(), Error> {
        let maybe_transformer_fn: Option<EntryTransformerFn> = match entry.function {
            leaf_0x1::LEAF_NUM => Some(common::update_feature_info_entry),
            leaf_0x7::LEAF_NUM => Some(amd::update_structured_extended_entry),
            leaf_0x8000001d::LEAF_NUM => Some(amd::update_extended_cache_topology_entry),
            0x8000_0002..=0x8000_0004 => Some(common::update_brand_string_entry),
            _ => None,
        };

        if let Some(transformer_fn) = maybe_transformer_fn {
            return transformer_fn(entry, vm_spec);
        }

        Ok(())
    }
}

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

    #[test]
    fn test_update_extended_cache_topology_entry() {
        use cpu_leaf::leaf_0x8000001d::*;

        let vm_spec = VmSpec::new(VENDOR_ID_AMD, 0, 1, false);
        let mut entry = &mut kvm_cpuid_entry2 {
            function: leaf_0x8000001d::LEAF_NUM,
            index: 0,
            flags: 0,
            eax: 0,
            ebx: 0,
            ecx: 0,
            edx: 0,
            padding: [0, 0, 0],
        };

        assert!(update_extended_cache_topology_entry(&mut entry, &vm_spec).is_ok());

        assert_eq!(entry.flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX, 1);
    }

    #[test]
    fn test_update_structured_extended_entry() {
        use cpu_leaf::leaf_0x7::index0::*;

        let vm_spec = VmSpec::new(VENDOR_ID_AMD, 0, 1, false);
        let mut entry = &mut kvm_cpuid_entry2 {
            function: leaf_0x7::LEAF_NUM,
            index: 0,
            flags: 0,
            eax: 0,
            ebx: 0,
            ecx: 0,
            edx: *(0 as u32).write_bit(edx::ARCH_CAPABILITIES_BITINDEX, true),
            padding: [0, 0, 0],
        };

        assert!(update_structured_extended_entry(&mut entry, &vm_spec).is_ok());

        assert_eq!(entry.edx.read_bit(edx::ARCH_CAPABILITIES_BITINDEX), false);
    }
}
<commit_msg>fix debug build warning<commit_after>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use super::*;

use kvm_bindings::KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
use kvm_ioctls::CpuId;

use bit_helper::BitHelper;
use cpu_leaf::*;
use transformer::common::use_host_cpuid_function;

pub fn update_structured_extended_entry(
    entry: &mut kvm_cpuid_entry2,
    _vm_spec: &VmSpec,
) -> Result<(), Error> {
    use cpu_leaf::leaf_0x7::index0::*;

    // KVM sets this bit no matter what but this feature is not supported by hardware
    entry.edx.write_bit(edx::ARCH_CAPABILITIES_BITINDEX, false);

    Ok(())
}

pub fn update_extended_cache_topology_entry(
    entry: &mut kvm_cpuid_entry2,
    vm_spec: &VmSpec,
) -> Result<(), Error> {
    entry.flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;

    common::update_cache_parameters_entry(entry, vm_spec)
}

pub struct AmdCpuidTransformer {}

impl CpuidTransformer for AmdCpuidTransformer {
    fn preprocess_cpuid(&self, cpuid: &mut CpuId) -> Result<(), Error> {
        use_host_cpuid_function(cpuid, leaf_0x8000001d::LEAF_NUM)
    }

    fn transform_entry(&self, entry: &mut kvm_cpuid_entry2, vm_spec: &VmSpec) -> Result<(), Error> {
        let maybe_transformer_fn: Option<EntryTransformerFn> = match entry.function {
            leaf_0x1::LEAF_NUM => Some(common::update_feature_info_entry),
            leaf_0x7::LEAF_NUM => Some(amd::update_structured_extended_entry),
            leaf_0x8000001d::LEAF_NUM => Some(amd::update_extended_cache_topology_entry),
            0x8000_0002..=0x8000_0004 => Some(common::update_brand_string_entry),
            _ => None,
        };

        if let Some(transformer_fn) = maybe_transformer_fn {
            return transformer_fn(entry, vm_spec);
        }

        Ok(())
    }
}

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

    #[test]
    fn test_update_extended_cache_topology_entry() {
        let vm_spec = VmSpec::new(VENDOR_ID_AMD, 0, 1, false);
        let mut entry = &mut kvm_cpuid_entry2 {
            function: leaf_0x8000001d::LEAF_NUM,
            index: 0,
            flags: 0,
            eax: 0,
            ebx: 0,
            ecx: 0,
            edx: 0,
            padding: [0, 0, 0],
        };

        assert!(update_extended_cache_topology_entry(&mut entry, &vm_spec).is_ok());

        assert_eq!(entry.flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX, 1);
    }

    #[test]
    fn test_update_structured_extended_entry() {
        use cpu_leaf::leaf_0x7::index0::*;

        let vm_spec = VmSpec::new(VENDOR_ID_AMD, 0, 1, false);
        let mut entry = &mut kvm_cpuid_entry2 {
            function: leaf_0x7::LEAF_NUM,
            index: 0,
            flags: 0,
            eax: 0,
            ebx: 0,
            ecx: 0,
            edx: *(0 as u32).write_bit(edx::ARCH_CAPABILITIES_BITINDEX, true),
            padding: [0, 0, 0],
        };

        assert!(update_structured_extended_entry(&mut entry, &vm_spec).is_ok());

        assert_eq!(entry.edx.read_bit(edx::ARCH_CAPABILITIES_BITINDEX), false);
    }
}
<|endoftext|>


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

use super::state_machine::*;

///
/// Represents a state machine with no states
///
pub struct EmptyStateMachine {
}

impl<InputSymbol, OutputSymbol> StateMachine<InputSymbol, OutputSymbol> for EmptyStateMachine {
    ///
    /// Returns the number of states in this state machine
    ///
    fn count_states(&self) -> StateId {
        1
    }

    ///
    /// Returns the transitions for a particular symbol
    ///
    fn get_transitions_for_state(&self, _state: StateId) -> Vec<(InputSymbol, StateId)> {
        vec![]
    }

    ///
    /// If a state is an accepting state, then this returns the output symbol that should be produced if this is the longest match
    ///
    fn output_symbol_for_state(&self, _state: StateId) -> Option<OutputSymbol> {
        None
    }
}
<commit_msg>Implement Clone for the empty state machine<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

use super::state_machine::*;

///
/// Represents a state machine with no states
///
#[derive(Clone)]
pub struct EmptyStateMachine {
}

impl<InputSymbol, OutputSymbol> StateMachine<InputSymbol, OutputSymbol> for EmptyStateMachine {
    ///
    /// Returns the number of states in this state machine
    ///
    fn count_states(&self) -> StateId {
        1
    }

    ///
    /// Returns the transitions for a particular symbol
    ///
    fn get_transitions_for_state(&self, _state: StateId) -> Vec<(InputSymbol, StateId)> {
        vec![]
    }

    ///
    /// If a state is an accepting state, then this returns the output symbol that should be produced if this is the longest match
    ///
    fn output_symbol_for_state(&self, _state: StateId) -> Option<&OutputSymbol> {
        None
    }
}
<|endoftext|>


<commit_before>// Copyright 2022 Collabora, Ltd.
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

use std::{error::Error, fmt, str::FromStr};

use onig::{Regex, RegexOptions, Syntax};

use super::Matcher;

#[derive(Debug)]
pub struct ParseRegexTypeError(String);

impl Error for ParseRegexTypeError {}

impl fmt::Display for ParseRegexTypeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Invalid regex type: {} (must be one of {})",
            self.0,
            RegexType::VALUES
                .iter()
                .map(|t| format!("'{}'", t))
                .collect::<Vec<_>>()
                .join(", ")
        )
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RegexType {
    Emacs,
    Grep,
    PosixBasic,
    PosixExtended,
}

impl RegexType {
    pub const VALUES: &'static [Self] = &[
        Self::Emacs,
        Self::Grep,
        Self::PosixBasic,
        Self::PosixExtended,
    ];
}

impl fmt::Display for RegexType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            RegexType::Emacs => write!(f, "emacs"),
            RegexType::Grep => write!(f, "grep"),
            RegexType::PosixBasic => write!(f, "posix-basic"),
            RegexType::PosixExtended => write!(f, "posix-extended"),
        }
    }
}

impl FromStr for RegexType {
    type Err = ParseRegexTypeError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "emacs" => Ok(Self::Emacs),
            "grep" => Ok(Self::Grep),
            "posix-basic" => Ok(Self::PosixBasic),
            "posix-extended" => Ok(Self::PosixExtended),
            _ => Err(ParseRegexTypeError(s.to_owned())),
        }
    }
}

impl Default for RegexType {
    fn default() -> Self {
        Self::Emacs
    }
}

pub struct RegexMatcher {
    regex: Regex,
}

impl RegexMatcher {
    pub fn new(
        regex_type: RegexType,
        pattern: &str,
        ignore_case: bool,
    ) -> Result<Self, Box<dyn Error>> {
        let syntax = match regex_type {
            RegexType::Emacs => Syntax::emacs(),
            RegexType::Grep => Syntax::grep(),
            RegexType::PosixBasic => Syntax::posix_basic(),
            RegexType::PosixExtended => Syntax::posix_extended(),
        };

        let regex = Regex::with_options(
            pattern,
            if ignore_case {
                RegexOptions::REGEX_OPTION_IGNORECASE
            } else {
                RegexOptions::REGEX_OPTION_NONE
            },
            syntax,
        )?;
        Ok(Self { regex })
    }
}

impl Matcher for RegexMatcher {
    fn matches(&self, file_info: &walkdir::DirEntry, _: &mut super::MatcherIO) -> bool {
        self.regex
            .is_match(file_info.path().to_string_lossy().as_ref())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::find::matchers::tests::get_dir_entry_for;
    use crate::find::matchers::Matcher;
    use crate::find::tests::FakeDependencies;

    const POSIX_BASIC_INTERVALS_RE: &str = r".*/ab\{1,3\}c";
    const POSIX_EXTENDED_INTERVALS_RE: &str = r".*/ab{1,3}c";
    const EMACS_AND_POSIX_EXTENDED_KLEENE_PLUS: &str = r".*/ab+c";

    // Variants of fix_up_slashes that properly escape the forward slashes for
    // being in a regex.
    #[cfg(windows)]
    fn fix_up_regex_slashes(re: &str) -> String {
        re.replace("/", r"\\")
    }

    #[cfg(not(windows))]
    fn fix_up_regex_slashes(re: &str) -> String {
        re.to_owned()
    }

    #[test]
    fn case_sensitive_matching() {
        let abbbc = get_dir_entry_for("test_data/simple", "abbbc");
        let matcher =
            RegexMatcher::new(RegexType::Emacs, &fix_up_regex_slashes(".*/ab.BC"), false).unwrap();
        let deps = FakeDependencies::new();
        assert!(!matcher.matches(&abbbc, &mut deps.new_matcher_io()));
    }

    #[test]
    fn case_insensitive_matching() {
        let abbbc = get_dir_entry_for("test_data/simple", "abbbc");
        let matcher =
            RegexMatcher::new(RegexType::Emacs, &fix_up_regex_slashes(".*/ab.BC"), true).unwrap();
        let deps = FakeDependencies::new();
        assert!(matcher.matches(&abbbc, &mut deps.new_matcher_io()));
    }

    #[test]
    fn emacs_regex() {
        // Emacs syntax is mostly the same as POSIX extended but with escaped
        // brace intervals.
        let abbbc = get_dir_entry_for("test_data/simple", "abbbc");

        let matcher = RegexMatcher::new(
            RegexType::Emacs,
            &fix_up_regex_slashes(EMACS_AND_POSIX_EXTENDED_KLEENE_PLUS),
            true,
        )
        .unwrap();
        let deps = FakeDependencies::new();
        assert!(matcher.matches(&abbbc, &mut deps.new_matcher_io()));

        let matcher = RegexMatcher::new(
            RegexType::Emacs,
            &fix_up_regex_slashes(POSIX_EXTENDED_INTERVALS_RE),
            true,
        )
        .unwrap();
        let deps = FakeDependencies::new();
        assert!(!matcher.matches(&abbbc, &mut deps.new_matcher_io()));
    }

    #[test]
    fn posix_basic_regex() {
        let abbbc = get_dir_entry_for("test_data/simple", "abbbc");

        let matcher = RegexMatcher::new(
            RegexType::PosixBasic,
            &fix_up_regex_slashes(POSIX_BASIC_INTERVALS_RE),
            true,
        )
        .unwrap();
        let deps = FakeDependencies::new();
        assert!(matcher.matches(&abbbc, &mut deps.new_matcher_io()));

        let matcher = RegexMatcher::new(
            RegexType::PosixBasic,
            &fix_up_regex_slashes(POSIX_EXTENDED_INTERVALS_RE),
            true,
        )
        .unwrap();
        let deps = FakeDependencies::new();
        assert!(!matcher.matches(&abbbc, &mut deps.new_matcher_io()));
    }

    #[test]
    fn posix_extended_regex() {
        let abbbc = get_dir_entry_for("test_data/simple", "abbbc");

        let matcher = RegexMatcher::new(
            RegexType::PosixExtended,
            &fix_up_regex_slashes(POSIX_EXTENDED_INTERVALS_RE),
            true,
        )
        .unwrap();
        let deps = FakeDependencies::new();
        assert!(matcher.matches(&abbbc, &mut deps.new_matcher_io()));

        let matcher = RegexMatcher::new(
            RegexType::PosixExtended,
            &fix_up_regex_slashes(POSIX_BASIC_INTERVALS_RE),
            true,
        )
        .unwrap();
        let deps = FakeDependencies::new();
        assert!(!matcher.matches(&abbbc, &mut deps.new_matcher_io()));
    }
}
<commit_msg>find/matchers: Add the `ed` and `sed` regex types<commit_after>// Copyright 2022 Collabora, Ltd.
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

use std::{error::Error, fmt, str::FromStr};

use onig::{Regex, RegexOptions, Syntax};

use super::Matcher;

#[derive(Debug)]
pub struct ParseRegexTypeError(String);

impl Error for ParseRegexTypeError {}

impl fmt::Display for ParseRegexTypeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Invalid regex type: {} (must be one of {})",
            self.0,
            RegexType::VALUES
                .iter()
                .map(|t| format!("'{}'", t))
                .collect::<Vec<_>>()
                .join(", ")
        )
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RegexType {
    Emacs,
    Grep,
    PosixBasic,
    PosixExtended,
}

impl RegexType {
    pub const VALUES: &'static [Self] = &[
        Self::Emacs,
        Self::Grep,
        Self::PosixBasic,
        Self::PosixExtended,
    ];
}

impl fmt::Display for RegexType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            RegexType::Emacs => write!(f, "emacs"),
            RegexType::Grep => write!(f, "grep"),
            RegexType::PosixBasic => write!(f, "posix-basic"),
            RegexType::PosixExtended => write!(f, "posix-extended"),
        }
    }
}

impl FromStr for RegexType {
    type Err = ParseRegexTypeError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "emacs" => Ok(Self::Emacs),
            "grep" => Ok(Self::Grep),
            "posix-basic" => Ok(Self::PosixBasic),
            "posix-extended" => Ok(Self::PosixExtended),
            // ed and sed are the same as posix-basic
            "ed" | "sed" => Ok(Self::PosixBasic),
            _ => Err(ParseRegexTypeError(s.to_owned())),
        }
    }
}

impl Default for RegexType {
    fn default() -> Self {
        Self::Emacs
    }
}

pub struct RegexMatcher {
    regex: Regex,
}

impl RegexMatcher {
    pub fn new(
        regex_type: RegexType,
        pattern: &str,
        ignore_case: bool,
    ) -> Result<Self, Box<dyn Error>> {
        let syntax = match regex_type {
            RegexType::Emacs => Syntax::emacs(),
            RegexType::Grep => Syntax::grep(),
            RegexType::PosixBasic => Syntax::posix_basic(),
            RegexType::PosixExtended => Syntax::posix_extended(),
        };

        let regex = Regex::with_options(
            pattern,
            if ignore_case {
                RegexOptions::REGEX_OPTION_IGNORECASE
            } else {
                RegexOptions::REGEX_OPTION_NONE
            },
            syntax,
        )?;
        Ok(Self { regex })
    }
}

impl Matcher for RegexMatcher {
    fn matches(&self, file_info: &walkdir::DirEntry, _: &mut super::MatcherIO) -> bool {
        self.regex
            .is_match(file_info.path().to_string_lossy().as_ref())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::find::matchers::tests::get_dir_entry_for;
    use crate::find::matchers::Matcher;
    use crate::find::tests::FakeDependencies;

    const POSIX_BASIC_INTERVALS_RE: &str = r".*/ab\{1,3\}c";
    const POSIX_EXTENDED_INTERVALS_RE: &str = r".*/ab{1,3}c";
    const EMACS_AND_POSIX_EXTENDED_KLEENE_PLUS: &str = r".*/ab+c";

    // Variants of fix_up_slashes that properly escape the forward slashes for
    // being in a regex.
    #[cfg(windows)]
    fn fix_up_regex_slashes(re: &str) -> String {
        re.replace("/", r"\\")
    }

    #[cfg(not(windows))]
    fn fix_up_regex_slashes(re: &str) -> String {
        re.to_owned()
    }

    #[test]
    fn case_sensitive_matching() {
        let abbbc = get_dir_entry_for("test_data/simple", "abbbc");
        let matcher =
            RegexMatcher::new(RegexType::Emacs, &fix_up_regex_slashes(".*/ab.BC"), false).unwrap();
        let deps = FakeDependencies::new();
        assert!(!matcher.matches(&abbbc, &mut deps.new_matcher_io()));
    }

    #[test]
    fn case_insensitive_matching() {
        let abbbc = get_dir_entry_for("test_data/simple", "abbbc");
        let matcher =
            RegexMatcher::new(RegexType::Emacs, &fix_up_regex_slashes(".*/ab.BC"), true).unwrap();
        let deps = FakeDependencies::new();
        assert!(matcher.matches(&abbbc, &mut deps.new_matcher_io()));
    }

    #[test]
    fn emacs_regex() {
        // Emacs syntax is mostly the same as POSIX extended but with escaped
        // brace intervals.
        let abbbc = get_dir_entry_for("test_data/simple", "abbbc");

        let matcher = RegexMatcher::new(
            RegexType::Emacs,
            &fix_up_regex_slashes(EMACS_AND_POSIX_EXTENDED_KLEENE_PLUS),
            true,
        )
        .unwrap();
        let deps = FakeDependencies::new();
        assert!(matcher.matches(&abbbc, &mut deps.new_matcher_io()));

        let matcher = RegexMatcher::new(
            RegexType::Emacs,
            &fix_up_regex_slashes(POSIX_EXTENDED_INTERVALS_RE),
            true,
        )
        .unwrap();
        let deps = FakeDependencies::new();
        assert!(!matcher.matches(&abbbc, &mut deps.new_matcher_io()));
    }

    #[test]
    fn posix_basic_regex() {
        let abbbc = get_dir_entry_for("test_data/simple", "abbbc");

        let matcher = RegexMatcher::new(
            RegexType::PosixBasic,
            &fix_up_regex_slashes(POSIX_BASIC_INTERVALS_RE),
            true,
        )
        .unwrap();
        let deps = FakeDependencies::new();
        assert!(matcher.matches(&abbbc, &mut deps.new_matcher_io()));

        let matcher = RegexMatcher::new(
            RegexType::PosixBasic,
            &fix_up_regex_slashes(POSIX_EXTENDED_INTERVALS_RE),
            true,
        )
        .unwrap();
        let deps = FakeDependencies::new();
        assert!(!matcher.matches(&abbbc, &mut deps.new_matcher_io()));
    }

    #[test]
    fn posix_extended_regex() {
        let abbbc = get_dir_entry_for("test_data/simple", "abbbc");

        let matcher = RegexMatcher::new(
            RegexType::PosixExtended,
            &fix_up_regex_slashes(POSIX_EXTENDED_INTERVALS_RE),
            true,
        )
        .unwrap();
        let deps = FakeDependencies::new();
        assert!(matcher.matches(&abbbc, &mut deps.new_matcher_io()));

        let matcher = RegexMatcher::new(
            RegexType::PosixExtended,
            &fix_up_regex_slashes(POSIX_BASIC_INTERVALS_RE),
            true,
        )
        .unwrap();
        let deps = FakeDependencies::new();
        assert!(!matcher.matches(&abbbc, &mut deps.new_matcher_io()));
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::time::{SystemTime, UNIX_EPOCH};

use domain::wallet::Tags;
use errors::prelude::*;
use services::wallet::{WalletService, WalletRecord};
use api::{WalletHandle, PoolHandle, CommandHandle};
use commands::{Command, CommandExecutor};
use commands::ledger::LedgerCommand;

use api::next_command_handle;

const CRED_DEF_CACHE: &str = "cred_def_cache";
const SCHEMA_CACHE: &str = "schema_cache";

pub enum CacheCommand {
    GetSchema(PoolHandle,
              WalletHandle,
              String, // submitter_did
              String, // id
              String, // options_json
              Box<Fn(IndyResult<String>) + Send>),
    GetSchemaContinue(
        WalletHandle,
        IndyResult<(String, String)>, // ledger_response
        GetCacheOptions,              // options
        CommandHandle,                          // cb_id
    ),
    GetCredDef(PoolHandle,
               WalletHandle,
               String, // submitter_did
               String, // id
               String, // options_json
               Box<Fn(IndyResult<String>) + Send>),
    GetCredDefContinue(
        WalletHandle,
        IndyResult<(String, String)>, // ledger_response
        GetCacheOptions,              // options
        CommandHandle,                          // cb_id
    ),
    PurgeSchemaCache(WalletHandle,
                     String, // options json
                     Box<Fn(IndyResult<()>) + Send>),
    PurgeCredDefCache(WalletHandle,
                      String, // options json
                      Box<Fn(IndyResult<()>) + Send>),
}

pub struct CacheCommandExecutor {
    wallet_service: Rc<WalletService>,

    pending_callbacks: RefCell<HashMap<CommandHandle, Box<Fn(IndyResult<String>)>>>,
}

macro_rules! check_cache {
    ($cache: ident, $options: ident, $cb: ident) => {
    if let Some(cache) = $cache {
            let min_fresh = $options.min_fresh.unwrap_or(-1);
            if min_fresh >= 0 {
                let ts = match SystemTime::now().duration_since(UNIX_EPOCH) {
                    Ok(ts) => ts.as_secs() as i32,
                    Err(err) => {
                        error!("Cannot get time: {:?}", err);
                        return $cb(Err(IndyError::from_msg(IndyErrorKind::InvalidState, format!("Cannot get time: {:?}", err))))
                    }
                };
                if ts - min_fresh <= cache.get_tags().unwrap_or(&Tags::new()).get("timestamp").unwrap_or(&"-1".to_string()).parse().unwrap_or(-1) {
                    return $cb(Ok(cache.get_value().unwrap_or("").to_string()))
                }
            } else {
                return $cb(Ok(cache.get_value().unwrap_or("").to_string()))
            }
        }
    };
}

impl CacheCommandExecutor {
    pub fn new(wallet_service: Rc<WalletService>) -> CacheCommandExecutor {
        CacheCommandExecutor {
            wallet_service,
            pending_callbacks: RefCell::new(HashMap::new()),
        }
    }

    pub fn execute(&self, command: CacheCommand) {
        match command {
            CacheCommand::GetSchema(pool_handle, wallet_handle, submitter_did, id, options_json, cb) => {
                info!(target: "non_secrets_command_executor", "GetSchema command received");
                self.get_schema(pool_handle, wallet_handle, &submitter_did, &id, &options_json, cb);
            }
            CacheCommand::GetSchemaContinue(wallet_handle, ledger_response, options, cb_id) => {
                info!(target: "non_secrets_command_executor", "GetSchemaContinue command received");
                self._get_schema_continue(wallet_handle, ledger_response, options, cb_id);
            }
            CacheCommand::GetCredDef(pool_handle, wallet_handle, submitter_did, id, options_json, cb) => {
                info!(target: "non_secrets_command_executor", "GetCredDef command received");
                self.get_cred_def(pool_handle, wallet_handle, &submitter_did, &id, &options_json, cb);
            }
            CacheCommand::GetCredDefContinue(wallet_handle, ledger_response, options, cb_id) => {
                info!(target: "non_secrets_command_executor", "GetCredDefContinue command received");
                self._get_cred_def_continue(wallet_handle, ledger_response, options, cb_id);
            }
            CacheCommand::PurgeSchemaCache(wallet_handle, options_json, cb) => {
                info!(target: "non_secrets_command_executor", "PurgeSchemaCache command received");
                cb(self.purge_schema_cache(wallet_handle, &options_json));
            }
            CacheCommand::PurgeCredDefCache(wallet_handle, options_json, cb) => {
                info!(target: "non_secrets_command_executor", "PurgeCredDefCache command received");
                cb(self.purge_cred_def_cache(wallet_handle, &options_json));
            }
        }
    }

    fn get_schema(&self,
                  pool_handle: PoolHandle,
                  wallet_handle: WalletHandle,
                  submitter_did: &str,
                  id: &str,
                  options_json: &str,
                  cb: Box<Fn(IndyResult<String>) + Send>) {
        trace!("get_schema >>> pool_handle: {:?}, wallet_handle: {:?}, submitter_did: {:?}, id: {:?}, options_json: {:?}",
               pool_handle, wallet_handle, submitter_did, id, options_json);

        let options = try_cb!(serde_json::from_str::<GetCacheOptions>(options_json).to_indy(IndyErrorKind::InvalidStructure, "Cannot deserialize options"), cb);

        let cache = self.get_record_from_cache(wallet_handle, id, &options, SCHEMA_CACHE);
        let cache = try_cb!(cache, cb);

        check_cache!(cache, options, cb);

        if options.no_update.unwrap_or(false) {
            return cb(Err(IndyError::from(IndyErrorKind::LedgerItemNotFound)));
        }

        let cb_id = next_command_handle();
        self.pending_callbacks.borrow_mut().insert(cb_id, cb);

        CommandExecutor::instance().send(
            Command::Ledger(
                LedgerCommand::GetSchema(
                    pool_handle,
                    Some(submitter_did.to_string()),
                    id.to_string(),
                    Box::new(move |ledger_response| {
                        CommandExecutor::instance().send(
                            Command::Cache(
                                CacheCommand::GetSchemaContinue(
                                    wallet_handle,
                                    ledger_response,
                                    options.clone(),
                                    cb_id,
                                )
                            )
                        ).unwrap();
                    })
                )
            )
        ).unwrap();
    }

    fn _get_schema_continue(&self, wallet_handle: WalletHandle, ledger_response: IndyResult<(String, String)>, options: GetCacheOptions, cb_id: CommandHandle) {
        let cb = self.pending_callbacks.borrow_mut().remove(&cb_id).expect("FIXME INVALID STATE");

        let (schema_id, schema_json) = try_cb!(ledger_response, cb);

        if !options.no_store.unwrap_or(false) {
            let mut tags = Tags::new();
            let ts = match SystemTime::now().duration_since(UNIX_EPOCH) {
                Ok(ts) => ts.as_secs() as i32,
                Err(err) => {
                    warn!("Cannot get time: {:?}", err);
                    0
                }
            };
            tags.insert("timestamp".to_string(), ts.to_string());
            let _ = self.wallet_service.delete_record(wallet_handle, SCHEMA_CACHE, &schema_id);
            let _ = self.wallet_service.add_record(wallet_handle, SCHEMA_CACHE, &schema_id, &schema_json, &tags);
        }

        cb(Ok(schema_json));
    }

    fn get_cred_def(&self,
                    pool_handle: PoolHandle,
                    wallet_handle: WalletHandle,
                    submitter_did: &str,
                    id: &str,
                    options_json: &str,
                    cb: Box<Fn(IndyResult<String>) + Send>) {
        trace!("get_cred_def >>> pool_handle: {:?}, wallet_handle: {:?}, submitter_did: {:?}, id: {:?}, options_json: {:?}",
               pool_handle, wallet_handle, submitter_did, id, options_json);

        let options = try_cb!(serde_json::from_str::<GetCacheOptions>(options_json).to_indy(IndyErrorKind::InvalidStructure, "Cannot deserialize options"), cb);

        let cache = self.get_record_from_cache(wallet_handle, id, &options, CRED_DEF_CACHE);
        let cache = try_cb!(cache, cb);

        check_cache!(cache, options, cb);

        if options.no_update.unwrap_or(false) {
            return cb(Err(IndyError::from(IndyErrorKind::LedgerItemNotFound)));
        }

        let cb_id = next_command_handle();
        self.pending_callbacks.borrow_mut().insert(cb_id, cb);

        CommandExecutor::instance().send(
            Command::Ledger(
                LedgerCommand::GetCredDef(
                    pool_handle,
                    Some(submitter_did.to_string()),
                    id.to_string(),
                    Box::new(move |ledger_response| {
                        CommandExecutor::instance().send(
                            Command::Cache(
                                CacheCommand::GetCredDefContinue(
                                    wallet_handle,
                                    ledger_response,
                                    options.clone(),
                                    cb_id,
                                )
                            )
                        ).unwrap();
                    })
                )
            )
        ).unwrap();
    }

    fn get_record_from_cache(&self, wallet_handle: WalletHandle, id: &str, options: &GetCacheOptions, which_cache: &str) -> Result<Option<WalletRecord>, IndyError> {
        if !options.no_cache.unwrap_or(false) {
            let options_json = json!({
                "retrieveType": false,
                "retrieveValue": true,
                "retrieveTags": true,
            }).to_string();
            match self.wallet_service.get_record(wallet_handle, which_cache, id, &options_json) {
                Ok(record) => Ok(Some(record)),
                Err(err) => if err.kind() == IndyErrorKind::WalletItemNotFound { Ok(None) } else { Err(err) }
            }
        } else { Ok(None) }
    }

    fn _get_cred_def_continue(&self, wallet_handle: WalletHandle, ledger_response: IndyResult<(String, String)>, options: GetCacheOptions, cb_id: CommandHandle) {
        let cb = self.pending_callbacks.borrow_mut().remove(&cb_id).expect("FIXME INVALID STATE");

        let (cred_def_id, cred_def_json) = try_cb!(ledger_response, cb);

        if !options.no_store.unwrap_or(false) {
            let mut tags = Tags::new();
            let ts = match SystemTime::now().duration_since(UNIX_EPOCH) {
                Ok(ts) => ts.as_secs() as i32,
                Err(err) => {
                    warn!("Cannot get time: {:?}", err);
                    0
                }
            };
            tags.insert("timestamp".to_string(), ts.to_string());
            let _ = self.wallet_service.delete_record(wallet_handle, CRED_DEF_CACHE, &cred_def_id);
            let _ = self.wallet_service.add_record(wallet_handle, CRED_DEF_CACHE, &cred_def_id, &cred_def_json, &tags);
        }

        cb(Ok(cred_def_json));
    }

    fn purge_schema_cache(&self,
                          wallet_handle: WalletHandle,
                          options_json: &str) -> IndyResult<()> {
        trace!("purge_schema_cache >>> wallet_handle: {:?}, options_json: {:?}", wallet_handle, options_json);

        let options = serde_json::from_str::<PurgeOptions>(options_json)
            .to_indy(IndyErrorKind::InvalidStructure, "Cannot deserialize options")?;

        let max_age = options.max_age.unwrap_or(-1);
        let query_json = if max_age >= 0 {
            let ts = match SystemTime::now().duration_since(UNIX_EPOCH) {
                Ok(ts) => ts.as_secs() as i32,
                Err(err) => {
                    error!("Cannot get time: {:?}", err);
                    return Err(IndyError::from_msg(IndyErrorKind::InvalidState, format!("Cannot get time: {:?}", err)))
                }
            };
            json!({"timestamp": {"$lt": ts - max_age}}).to_string()
        } else {
            "{}".to_string()
        };

        let options_json = json!({
            "retrieveType": false,
            "retrieveValue": false,
            "retrieveTags": false,
        }).to_string();

        let mut search = self.wallet_service.search_records(
            wallet_handle,
            SCHEMA_CACHE,
            &query_json,
            &options_json,
        )?;

        while let Some(record) = search.fetch_next_record()? {
            self.wallet_service.delete_record(wallet_handle, SCHEMA_CACHE, record.get_id())?;
        }

        trace!("purge_schema_cache <<< res: ()");

        Ok(())
    }

    fn purge_cred_def_cache(&self,
                            wallet_handle: WalletHandle,
                            options_json: &str) -> IndyResult<()> {
        trace!("purge_cred_def_cache >>> wallet_handle: {:?}, options_json: {:?}", wallet_handle, options_json);

        let options = serde_json::from_str::<PurgeOptions>(options_json)
            .to_indy(IndyErrorKind::InvalidStructure, "Cannot deserialize options")?;

        let max_age = options.max_age.unwrap_or(-1);
        let query_json = if max_age >= 0 {
            let ts = match SystemTime::now().duration_since(UNIX_EPOCH) {
                Ok(ts) => ts.as_secs() as i32,
                Err(err) => {
                    error!("Cannot get time: {:?}", err);
                    return Err(IndyError::from_msg(IndyErrorKind::InvalidState, format!("Cannot get time: {:?}", err)))
                }
            };
            json!({"timestamp": {"$lt": ts - max_age}}).to_string()
        } else {
            "{}".to_string()
        };

        let options_json = json!({
            "retrieveType": false,
            "retrieveValue": false,
            "retrieveTags": false,
        }).to_string();

        let mut search = self.wallet_service.search_records(
            wallet_handle,
            CRED_DEF_CACHE,
            &query_json,
            &options_json,
        )?;

        while let Some(record) = search.fetch_next_record()? {
            self.wallet_service.delete_record(wallet_handle, CRED_DEF_CACHE, record.get_id())?;
        }

        trace!("purge_cred_def_cache <<< res: ()");

        Ok(())
    }
}

#[serde(rename_all = "camelCase")]
#[derive(Debug, Deserialize, Serialize)]
struct PurgeOptions {
    pub max_age: Option<i32>,
}

#[serde(rename_all = "camelCase")]
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct GetCacheOptions {
    pub no_cache: Option<bool>,     // Skip usage of cache,
    pub no_update: Option<bool>,    // Use only cached data, do not try to update.
    pub no_store: Option<bool>,     // Skip storing fresh data if updated
    pub min_fresh: Option<i32>,     // Return cached data if not older than this many seconds. -1 means do not check age.
}
<commit_msg>duplicate code _delete_and_add_record<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::time::{SystemTime, UNIX_EPOCH};

use domain::wallet::Tags;
use errors::prelude::*;
use services::wallet::{WalletService, WalletRecord};
use api::{WalletHandle, PoolHandle, CommandHandle};
use commands::{Command, CommandExecutor};
use commands::ledger::LedgerCommand;

use api::next_command_handle;

const CRED_DEF_CACHE: &str = "cred_def_cache";
const SCHEMA_CACHE: &str = "schema_cache";

pub enum CacheCommand {
    GetSchema(PoolHandle,
              WalletHandle,
              String, // submitter_did
              String, // id
              String, // options_json
              Box<Fn(IndyResult<String>) + Send>),
    GetSchemaContinue(
        WalletHandle,
        IndyResult<(String, String)>, // ledger_response
        GetCacheOptions,              // options
        CommandHandle,                          // cb_id
    ),
    GetCredDef(PoolHandle,
               WalletHandle,
               String, // submitter_did
               String, // id
               String, // options_json
               Box<Fn(IndyResult<String>) + Send>),
    GetCredDefContinue(
        WalletHandle,
        IndyResult<(String, String)>, // ledger_response
        GetCacheOptions,              // options
        CommandHandle,                          // cb_id
    ),
    PurgeSchemaCache(WalletHandle,
                     String, // options json
                     Box<Fn(IndyResult<()>) + Send>),
    PurgeCredDefCache(WalletHandle,
                      String, // options json
                      Box<Fn(IndyResult<()>) + Send>),
}

pub struct CacheCommandExecutor {
    wallet_service: Rc<WalletService>,

    pending_callbacks: RefCell<HashMap<CommandHandle, Box<Fn(IndyResult<String>)>>>,
}

macro_rules! check_cache {
    ($cache: ident, $options: ident, $cb: ident) => {
    if let Some(cache) = $cache {
            let min_fresh = $options.min_fresh.unwrap_or(-1);
            if min_fresh >= 0 {
                let ts = match SystemTime::now().duration_since(UNIX_EPOCH) {
                    Ok(ts) => ts.as_secs() as i32,
                    Err(err) => {
                        error!("Cannot get time: {:?}", err);
                        return $cb(Err(IndyError::from_msg(IndyErrorKind::InvalidState, format!("Cannot get time: {:?}", err))))
                    }
                };
                if ts - min_fresh <= cache.get_tags().unwrap_or(&Tags::new()).get("timestamp").unwrap_or(&"-1".to_string()).parse().unwrap_or(-1) {
                    return $cb(Ok(cache.get_value().unwrap_or("").to_string()))
                }
            } else {
                return $cb(Ok(cache.get_value().unwrap_or("").to_string()))
            }
        }
    };
}

impl CacheCommandExecutor {
    pub fn new(wallet_service: Rc<WalletService>) -> CacheCommandExecutor {
        CacheCommandExecutor {
            wallet_service,
            pending_callbacks: RefCell::new(HashMap::new()),
        }
    }

    pub fn execute(&self, command: CacheCommand) {
        match command {
            CacheCommand::GetSchema(pool_handle, wallet_handle, submitter_did, id, options_json, cb) => {
                info!(target: "non_secrets_command_executor", "GetSchema command received");
                self.get_schema(pool_handle, wallet_handle, &submitter_did, &id, &options_json, cb);
            }
            CacheCommand::GetSchemaContinue(wallet_handle, ledger_response, options, cb_id) => {
                info!(target: "non_secrets_command_executor", "GetSchemaContinue command received");
                self._get_schema_continue(wallet_handle, ledger_response, options, cb_id);
            }
            CacheCommand::GetCredDef(pool_handle, wallet_handle, submitter_did, id, options_json, cb) => {
                info!(target: "non_secrets_command_executor", "GetCredDef command received");
                self.get_cred_def(pool_handle, wallet_handle, &submitter_did, &id, &options_json, cb);
            }
            CacheCommand::GetCredDefContinue(wallet_handle, ledger_response, options, cb_id) => {
                info!(target: "non_secrets_command_executor", "GetCredDefContinue command received");
                self._get_cred_def_continue(wallet_handle, ledger_response, options, cb_id);
            }
            CacheCommand::PurgeSchemaCache(wallet_handle, options_json, cb) => {
                info!(target: "non_secrets_command_executor", "PurgeSchemaCache command received");
                cb(self.purge_schema_cache(wallet_handle, &options_json));
            }
            CacheCommand::PurgeCredDefCache(wallet_handle, options_json, cb) => {
                info!(target: "non_secrets_command_executor", "PurgeCredDefCache command received");
                cb(self.purge_cred_def_cache(wallet_handle, &options_json));
            }
        }
    }

    fn get_schema(&self,
                  pool_handle: PoolHandle,
                  wallet_handle: WalletHandle,
                  submitter_did: &str,
                  id: &str,
                  options_json: &str,
                  cb: Box<Fn(IndyResult<String>) + Send>) {
        trace!("get_schema >>> pool_handle: {:?}, wallet_handle: {:?}, submitter_did: {:?}, id: {:?}, options_json: {:?}",
               pool_handle, wallet_handle, submitter_did, id, options_json);

        let options = try_cb!(serde_json::from_str::<GetCacheOptions>(options_json).to_indy(IndyErrorKind::InvalidStructure, "Cannot deserialize options"), cb);

        let cache = self.get_record_from_cache(wallet_handle, id, &options, SCHEMA_CACHE);
        let cache = try_cb!(cache, cb);

        check_cache!(cache, options, cb);

        if options.no_update.unwrap_or(false) {
            return cb(Err(IndyError::from(IndyErrorKind::LedgerItemNotFound)));
        }

        let cb_id = next_command_handle();
        self.pending_callbacks.borrow_mut().insert(cb_id, cb);

        CommandExecutor::instance().send(
            Command::Ledger(
                LedgerCommand::GetSchema(
                    pool_handle,
                    Some(submitter_did.to_string()),
                    id.to_string(),
                    Box::new(move |ledger_response| {
                        CommandExecutor::instance().send(
                            Command::Cache(
                                CacheCommand::GetSchemaContinue(
                                    wallet_handle,
                                    ledger_response,
                                    options.clone(),
                                    cb_id,
                                )
                            )
                        ).unwrap();
                    })
                )
            )
        ).unwrap();
    }

    fn _delete_and_add_record(&self,
                              wallet_handle: WalletHandle,
                              options: GetCacheOptions,
                              schema_id: &str,
                              schema_json: &str,
                              which_cache: &str) -> IndyResult<()>
    {
        if !options.no_store.unwrap_or(false) {
            let mut tags = Tags::new();
            let ts = match SystemTime::now().duration_since(UNIX_EPOCH) {
                Ok(ts) => ts.as_secs() as i32,
                Err(err) => {
                    warn!("Cannot get time: {:?}", err);
                    0
                }
            };
            tags.insert("timestamp".to_string(), ts.to_string());
            self.wallet_service.delete_record(wallet_handle, which_cache, &schema_id)?;
            self.wallet_service.add_record(wallet_handle, which_cache, &schema_id, &schema_json, &tags)?
        }
        Ok(())
    }

    fn _get_schema_continue(&self,
                            wallet_handle: WalletHandle,
                            ledger_response: IndyResult<(String, String)>,
                            options: GetCacheOptions, cb_id: CommandHandle) {
        let cb = self.pending_callbacks.borrow_mut().remove(&cb_id).expect("FIXME INVALID STATE");

        let (schema_id, schema_json) = try_cb!(ledger_response, cb);

        match self._delete_and_add_record(wallet_handle, options, &schema_id, &schema_json, SCHEMA_CACHE) {
            Ok(_) => cb(Ok(schema_json)),
            Err(err) => cb(Err(IndyError::from_msg(IndyErrorKind::InvalidState, format!("get_schema_continue failed: {:?}", err))))
        }
    }

    fn get_cred_def(&self,
                    pool_handle: PoolHandle,
                    wallet_handle: WalletHandle,
                    submitter_did: &str,
                    id: &str,
                    options_json: &str,
                    cb: Box<Fn(IndyResult<String>) + Send>) {
        trace!("get_cred_def >>> pool_handle: {:?}, wallet_handle: {:?}, submitter_did: {:?}, id: {:?}, options_json: {:?}",
               pool_handle, wallet_handle, submitter_did, id, options_json);

        let options = try_cb!(serde_json::from_str::<GetCacheOptions>(options_json).to_indy(IndyErrorKind::InvalidStructure, "Cannot deserialize options"), cb);

        let cache = self.get_record_from_cache(wallet_handle, id, &options, CRED_DEF_CACHE);
        let cache = try_cb!(cache, cb);

        check_cache!(cache, options, cb);

        if options.no_update.unwrap_or(false) {
            return cb(Err(IndyError::from(IndyErrorKind::LedgerItemNotFound)));
        }

        let cb_id = next_command_handle();
        self.pending_callbacks.borrow_mut().insert(cb_id, cb);

        CommandExecutor::instance().send(
            Command::Ledger(
                LedgerCommand::GetCredDef(
                    pool_handle,
                    Some(submitter_did.to_string()),
                    id.to_string(),
                    Box::new(move |ledger_response| {
                        CommandExecutor::instance().send(
                            Command::Cache(
                                CacheCommand::GetCredDefContinue(
                                    wallet_handle,
                                    ledger_response,
                                    options.clone(),
                                    cb_id,
                                )
                            )
                        ).unwrap();
                    })
                )
            )
        ).unwrap();
    }

    fn get_record_from_cache(&self, wallet_handle: WalletHandle, id: &str, options: &GetCacheOptions, which_cache: &str) -> Result<Option<WalletRecord>, IndyError> {
        if !options.no_cache.unwrap_or(false) {
            let options_json = json!({
                "retrieveType": false,
                "retrieveValue": true,
                "retrieveTags": true,
            }).to_string();
            match self.wallet_service.get_record(wallet_handle, which_cache, id, &options_json) {
                Ok(record) => Ok(Some(record)),
                Err(err) => if err.kind() == IndyErrorKind::WalletItemNotFound { Ok(None) } else { Err(err) }
            }
        } else { Ok(None) }
    }

    fn _get_cred_def_continue(&self, wallet_handle: WalletHandle, ledger_response: IndyResult<(String, String)>, options: GetCacheOptions, cb_id: CommandHandle) {
        let cb = self.pending_callbacks.borrow_mut().remove(&cb_id).expect("FIXME INVALID STATE");

        let (cred_def_id, cred_def_json) = try_cb!(ledger_response, cb);

        match self._delete_and_add_record(wallet_handle, options, &cred_def_id, &cred_def_json, CRED_DEF_CACHE) {
            Ok(_) => cb(Ok(cred_def_json)),
            Err(err) => cb(Err(IndyError::from_msg(IndyErrorKind::InvalidState, format!("get_cred_def_continue failed: {:?}", err))))
        }
    }

    fn purge_schema_cache(&self,
                          wallet_handle: WalletHandle,
                          options_json: &str) -> IndyResult<()> {
        trace!("purge_schema_cache >>> wallet_handle: {:?}, options_json: {:?}", wallet_handle, options_json);

        let options = serde_json::from_str::<PurgeOptions>(options_json)
            .to_indy(IndyErrorKind::InvalidStructure, "Cannot deserialize options")?;

        let max_age = options.max_age.unwrap_or(-1);
        let query_json = if max_age >= 0 {
            let ts = match SystemTime::now().duration_since(UNIX_EPOCH) {
                Ok(ts) => ts.as_secs() as i32,
                Err(err) => {
                    error!("Cannot get time: {:?}", err);
                    return Err(IndyError::from_msg(IndyErrorKind::InvalidState, format!("Cannot get time: {:?}", err)))
                }
            };
            json!({"timestamp": {"$lt": ts - max_age}}).to_string()
        } else {
            "{}".to_string()
        };

        let options_json = json!({
            "retrieveType": false,
            "retrieveValue": false,
            "retrieveTags": false,
        }).to_string();

        let mut search = self.wallet_service.search_records(
            wallet_handle,
            SCHEMA_CACHE,
            &query_json,
            &options_json,
        )?;

        while let Some(record) = search.fetch_next_record()? {
            self.wallet_service.delete_record(wallet_handle, SCHEMA_CACHE, record.get_id())?;
        }

        trace!("purge_schema_cache <<< res: ()");

        Ok(())
    }

    fn purge_cred_def_cache(&self,
                            wallet_handle: WalletHandle,
                            options_json: &str) -> IndyResult<()> {
        trace!("purge_cred_def_cache >>> wallet_handle: {:?}, options_json: {:?}", wallet_handle, options_json);

        let options = serde_json::from_str::<PurgeOptions>(options_json)
            .to_indy(IndyErrorKind::InvalidStructure, "Cannot deserialize options")?;

        let max_age = options.max_age.unwrap_or(-1);
        let query_json = if max_age >= 0 {
            let ts = match SystemTime::now().duration_since(UNIX_EPOCH) {
                Ok(ts) => ts.as_secs() as i32,
                Err(err) => {
                    error!("Cannot get time: {:?}", err);
                    return Err(IndyError::from_msg(IndyErrorKind::InvalidState, format!("Cannot get time: {:?}", err)))
                }
            };
            json!({"timestamp": {"$lt": ts - max_age}}).to_string()
        } else {
            "{}".to_string()
        };

        let options_json = json!({
            "retrieveType": false,
            "retrieveValue": false,
            "retrieveTags": false,
        }).to_string();

        let mut search = self.wallet_service.search_records(
            wallet_handle,
            CRED_DEF_CACHE,
            &query_json,
            &options_json,
        )?;

        while let Some(record) = search.fetch_next_record()? {
            self.wallet_service.delete_record(wallet_handle, CRED_DEF_CACHE, record.get_id())?;
        }

        trace!("purge_cred_def_cache <<< res: ()");

        Ok(())
    }
}

#[serde(rename_all = "camelCase")]
#[derive(Debug, Deserialize, Serialize)]
struct PurgeOptions {
    pub max_age: Option<i32>,
}

#[serde(rename_all = "camelCase")]
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct GetCacheOptions {
    pub no_cache: Option<bool>,     // Skip usage of cache,
    pub no_update: Option<bool>,    // Use only cached data, do not try to update.
    pub no_store: Option<bool>,     // Skip storing fresh data if updated
    pub min_fresh: Option<i32>,     // Return cached data if not older than this many seconds. -1 means do not check age.
}
<|endoftext|>


<commit_before>//! Error types for conversion to integral types.

use crate::convert::Infallible;
use crate::fmt;

/// The error type returned when a checked integral type conversion fails.
#[stable(feature = "try_from", since = "1.34.0")]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TryFromIntError(pub(crate) ());

impl TryFromIntError {
    #[unstable(
        feature = "int_error_internals",
        reason = "available through Error trait and this method should \
                  not be exposed publicly",
        issue = "none"
    )]
    #[doc(hidden)]
    pub fn __description(&self) -> &str {
        "out of range integral type conversion attempted"
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl fmt::Display for TryFromIntError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.__description().fmt(fmt)
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl From<Infallible> for TryFromIntError {
    fn from(x: Infallible) -> TryFromIntError {
        match x {}
    }
}

#[unstable(feature = "never_type", issue = "35121")]
impl From<!> for TryFromIntError {
    fn from(never: !) -> TryFromIntError {
        // Match rather than coerce to make sure that code like
        // `From<Infallible> for TryFromIntError` above will keep working
        // when `Infallible` becomes an alias to `!`.
        match never {}
    }
}

/// An error which can be returned when parsing an integer.
///
/// This error is used as the error type for the `from_str_radix()` functions
/// on the primitive integer types, such as [`i8::from_str_radix`].
///
/// # Potential causes
///
/// Among other causes, `ParseIntError` can be thrown because of leading or trailing whitespace
/// in the string e.g., when it is obtained from the standard input.
/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing.
///
/// [`str.trim()`]: ../../std/primitive.str.html#method.trim
/// [`i8::from_str_radix`]: ../../std/primitive.i8.html#method.from_str_radix
///
/// # Example
///
/// ```
/// if let Err(e) = i32::from_str_radix("a12", 10) {
///     println!("Failed conversion to i32: {}", e);
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct ParseIntError {
    pub(super) kind: IntErrorKind,
}

/// Enum to store the various types of errors that can cause parsing an integer to fail.
///
/// # Example
///
/// ```
/// # fn main() {
/// if let Err(e) = i32::from_str_radix("a12", 10) {
///     println!("Failed conversion to i32: {:?}", e.kind());
/// }
/// # }
/// ```
#[stable(feature = "int_error_matching", since = "1.47.0")]
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum IntErrorKind {
    /// Value being parsed is empty.
    ///
    /// Among other causes, this variant will be constructed when parsing an empty string.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    Empty,
    /// Contains an digit invalid in its context.
    ///
    /// Among other causes, this variant will be constructed when parsing a string that
    /// contains a non-asci char.
    ///
    /// This variant is also constructed when a `+` or `-` is misplaced within a sting
    /// either on its own or in the middle of a number.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    InvalidDigit(#[stable(feature = "int_error_matching", since = "1.47.0")] char),
    /// Integer is too large to store in target integer type.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    PosOverflow,
    /// Integer is too small to store in target integer type.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    NegOverflow,
    /// Value was Zero
    ///
    /// This variant will be emitted when the parsing string has a value of zero, which
    /// would be illegal for non-zero types.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    Zero,
}

impl ParseIntError {
    /// Outputs the detailed cause of parsing an integer failing.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    pub fn kind(&self) -> &IntErrorKind {
        &self.kind
    }
    #[unstable(
        feature = "int_error_internals",
        reason = "available through Error trait and this method should \
                  not be exposed publicly",
        issue = "none"
    )]
    #[doc(hidden)]
    pub fn __description(&self) -> &str {
        match self.kind {
            IntErrorKind::Empty => "cannot parse integer from empty string",
            IntErrorKind::InvalidDigit(_) => "invalid digit found in string",
            IntErrorKind::PosOverflow => "number too large to fit in target type",
            IntErrorKind::NegOverflow => "number too small to fit in target type",
            IntErrorKind::Zero => "number would be zero for non-zero type",
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for ParseIntError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.__description().fmt(f)
    }
}
<commit_msg>Fix spelling eror<commit_after>//! Error types for conversion to integral types.

use crate::convert::Infallible;
use crate::fmt;

/// The error type returned when a checked integral type conversion fails.
#[stable(feature = "try_from", since = "1.34.0")]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TryFromIntError(pub(crate) ());

impl TryFromIntError {
    #[unstable(
        feature = "int_error_internals",
        reason = "available through Error trait and this method should \
                  not be exposed publicly",
        issue = "none"
    )]
    #[doc(hidden)]
    pub fn __description(&self) -> &str {
        "out of range integral type conversion attempted"
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl fmt::Display for TryFromIntError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.__description().fmt(fmt)
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl From<Infallible> for TryFromIntError {
    fn from(x: Infallible) -> TryFromIntError {
        match x {}
    }
}

#[unstable(feature = "never_type", issue = "35121")]
impl From<!> for TryFromIntError {
    fn from(never: !) -> TryFromIntError {
        // Match rather than coerce to make sure that code like
        // `From<Infallible> for TryFromIntError` above will keep working
        // when `Infallible` becomes an alias to `!`.
        match never {}
    }
}

/// An error which can be returned when parsing an integer.
///
/// This error is used as the error type for the `from_str_radix()` functions
/// on the primitive integer types, such as [`i8::from_str_radix`].
///
/// # Potential causes
///
/// Among other causes, `ParseIntError` can be thrown because of leading or trailing whitespace
/// in the string e.g., when it is obtained from the standard input.
/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing.
///
/// [`str.trim()`]: ../../std/primitive.str.html#method.trim
/// [`i8::from_str_radix`]: ../../std/primitive.i8.html#method.from_str_radix
///
/// # Example
///
/// ```
/// if let Err(e) = i32::from_str_radix("a12", 10) {
///     println!("Failed conversion to i32: {}", e);
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct ParseIntError {
    pub(super) kind: IntErrorKind,
}

/// Enum to store the various types of errors that can cause parsing an integer to fail.
///
/// # Example
///
/// ```
/// # fn main() {
/// if let Err(e) = i32::from_str_radix("a12", 10) {
///     println!("Failed conversion to i32: {:?}", e.kind());
/// }
/// # }
/// ```
#[stable(feature = "int_error_matching", since = "1.47.0")]
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum IntErrorKind {
    /// Value being parsed is empty.
    ///
    /// Among other causes, this variant will be constructed when parsing an empty string.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    Empty,
    /// Contains an digit invalid in its context.
    ///
    /// Among other causes, this variant will be constructed when parsing a string that
    /// contains a non-asci char.
    ///
    /// This variant is also constructed when a `+` or `-` is misplaced within a string
    /// either on its own or in the middle of a number.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    InvalidDigit(#[stable(feature = "int_error_matching", since = "1.47.0")] char),
    /// Integer is too large to store in target integer type.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    PosOverflow,
    /// Integer is too small to store in target integer type.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    NegOverflow,
    /// Value was Zero
    ///
    /// This variant will be emitted when the parsing string has a value of zero, which
    /// would be illegal for non-zero types.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    Zero,
}

impl ParseIntError {
    /// Outputs the detailed cause of parsing an integer failing.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    pub fn kind(&self) -> &IntErrorKind {
        &self.kind
    }
    #[unstable(
        feature = "int_error_internals",
        reason = "available through Error trait and this method should \
                  not be exposed publicly",
        issue = "none"
    )]
    #[doc(hidden)]
    pub fn __description(&self) -> &str {
        match self.kind {
            IntErrorKind::Empty => "cannot parse integer from empty string",
            IntErrorKind::InvalidDigit(_) => "invalid digit found in string",
            IntErrorKind::PosOverflow => "number too large to fit in target type",
            IntErrorKind::NegOverflow => "number too small to fit in target type",
            IntErrorKind::Zero => "number would be zero for non-zero type",
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for ParseIntError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.__description().fmt(f)
    }
}
<|endoftext|>


<commit_before>//! Contains functions for computing SCCs and serializing graphs.
use std::io::{stderr, Read, Write, BufRead, BufReader, BufWriter};
use petgraph::{Graph};
use petgraph::algo::scc;
use petgraph::graph::NodeIndex;
use std::collections::HashMap;

fn load_graph<R>(source: &mut BufReader<R>) -> (Graph<u64, ()>, HashMap<u64, NodeIndex>) where R: Read {
    // read graph size
    let mut size = String::new();
    source.read_line(&mut size).ok().expect("failed to read graph size");

    let sz = size.trim().parse::<u64>().unwrap();
    writeln!(&mut stderr(), "Graph size is {} edges. Loading...", sz).unwrap();

    let mut graph = Graph::<u64, ()>::new();
    let mut nodes = HashMap::new();

    let mut cnt: u64 = 0;
    let step = if sz > 100 { sz/100 } else { 1 };
    for line in source.lines() {
        let l = line.unwrap();
        let (s, e, o) = scan_fmt!(&l, "{} {} {}", u64, u64, u8);
        let (start, end, oneway) = (s.unwrap(), e.unwrap(), o.unwrap());

        if start == end {
            continue
        }

        // adding a node erases the index, so for each unique index we need to keep
        // a map of the corresponding node <-> internal node id mappings. shitty,
        // but it seems to work.
        nodes.entry(start).or_insert_with(|| { graph.add_node(0) });
        nodes.entry(end).or_insert_with(|| { graph.add_node(0) });

        let si = nodes.get(&start).unwrap();
        let ei = nodes.get(&end).unwrap();

        graph.update_edge(*si, *ei, ());

        if oneway != 1 {
            graph.update_edge(*ei, *si, ());
        }
        cnt += 1;
        // print at every 0.5%
        if cnt%step == 0 {
            let quant = (cnt as f64/sz as f64)*100.0;
            write!(&mut stderr(), "\r{}/{} {:.0}%", cnt, sz, quant).unwrap();
        }
    }
    writeln!(&mut stderr(), "").unwrap();

    (graph, nodes)
}

/// Computes the strongly connected components. Takes a graph stream as an
/// input where the format is as follows:
///
/// ```ignore
/// num_edges
/// id1 id2 oneway
/// id1 id2 oneway
/// ...
/// id1 id2 oneway
/// ```
///
/// where `id1` is the start of the edge, `id2` is the end of the edge,
/// and `oneway` is **0** if the edge is bidirectional (id2->id1 is permitted)
/// or **1** if `id2` -> `id1` is not allowed. `num_edges` is the number of edges in the
/// file. **output** is a function that can consume the component vectors and the index
/// of the current component vector.
pub fn compute<R, F>(source: &mut BufReader<R>, mut output: F) where R: Read, F: FnMut(Vec<u64>, usize) {
    let (graph, nodes) = load_graph(source);
    writeln!(&mut stderr(), "Graph loaded. Computing SCCs.").unwrap();
    let mut comps: Vec<Vec<_>> = scc(&graph);
    writeln!(&mut stderr(), "Calculated {} components.", comps.len()).unwrap();

    // sort by size, and reverse
    comps.sort_by(|v, w| v.len().cmp(&w.len()));
    comps.reverse();
    // find out the real nodes
    let inverse_nodes: HashMap<_,_> = nodes.into_iter().map(|(k, v)| (v, k)).collect();
    for (i, comp) in comps.iter().enumerate() {
        let real_nodes = comp.into_iter().map(|n| *inverse_nodes.get(&n).unwrap()).collect();
        output(real_nodes, i);
    }
}

/// Serializes the contents of the component into a stream where each node is
/// separated by `delim`. Panics if target cannot be opened.
pub fn serialize<W>(comp: Vec<u64>, target: &mut BufWriter<W>, delim: u8) where W: Write {
    for node in comp {
        target.write(node.to_string().as_bytes()).unwrap();
        target.write(&[delim]).unwrap();
    }
}
<commit_msg>Add circular edges to the graph just because.<commit_after>//! Contains functions for computing SCCs and serializing graphs.
use std::io::{stderr, Read, Write, BufRead, BufReader, BufWriter};
use petgraph::{Graph};
use petgraph::algo::scc;
use petgraph::graph::NodeIndex;
use std::collections::HashMap;

fn load_graph<R>(source: &mut BufReader<R>) -> (Graph<u64, ()>, HashMap<u64, NodeIndex>) where R: Read {
    // read graph size
    let mut size = String::new();
    source.read_line(&mut size).ok().expect("failed to read graph size");

    let sz = size.trim().parse::<u64>().unwrap();
    writeln!(&mut stderr(), "Graph size is {} edges. Loading...", sz).unwrap();

    let mut graph = Graph::<u64, ()>::new();
    let mut nodes = HashMap::new();

    let mut cnt: u64 = 0;
    let step = if sz > 100 { sz/100 } else { 1 };
    for line in source.lines() {
        let l = line.unwrap();
        let (s, e, o) = scan_fmt!(&l, "{} {} {}", u64, u64, u8);
        let (start, end, oneway) = (s.unwrap(), e.unwrap(), o.unwrap());

        // adding a node erases the index, so for each unique index we need to keep
        // a map of the corresponding node <-> internal node id mappings. shitty,
        // but it seems to work.
        nodes.entry(start).or_insert_with(|| { graph.add_node(0) });
        nodes.entry(end).or_insert_with(|| { graph.add_node(0) });

        let si = nodes.get(&start).unwrap();
        let ei = nodes.get(&end).unwrap();

        graph.update_edge(*si, *ei, ());

        if oneway != 1 {
            graph.update_edge(*ei, *si, ());
        }
        cnt += 1;
        // print at every 0.5%
        if cnt%step == 0 {
            let quant = (cnt as f64/sz as f64)*100.0;
            write!(&mut stderr(), "\r{}/{} {:.0}%", cnt, sz, quant).unwrap();
        }
    }
    writeln!(&mut stderr(), "").unwrap();

    (graph, nodes)
}

/// Computes the strongly connected components. Takes a graph stream as an
/// input where the format is as follows:
///
/// ```ignore
/// num_edges
/// id1 id2 oneway
/// id1 id2 oneway
/// ...
/// id1 id2 oneway
/// ```
///
/// where `id1` is the start of the edge, `id2` is the end of the edge,
/// and `oneway` is **0** if the edge is bidirectional (id2->id1 is permitted)
/// or **1** if `id2` -> `id1` is not allowed. `num_edges` is the number of edges in the
/// file. **output** is a function that can consume the component vectors and the index
/// of the current component vector.
pub fn compute<R, F>(source: &mut BufReader<R>, mut output: F) where R: Read, F: FnMut(Vec<u64>, usize) {
    let (graph, nodes) = load_graph(source);
    writeln!(&mut stderr(), "Graph loaded. Computing SCCs.").unwrap();
    let mut comps: Vec<Vec<_>> = scc(&graph);
    writeln!(&mut stderr(), "Calculated {} components.", comps.len()).unwrap();

    // sort by size, and reverse
    comps.sort_by(|v, w| v.len().cmp(&w.len()));
    comps.reverse();
    // find out the real nodes
    let inverse_nodes: HashMap<_,_> = nodes.into_iter().map(|(k, v)| (v, k)).collect();
    for (i, comp) in comps.iter().enumerate() {
        let real_nodes = comp.into_iter().map(|n| *inverse_nodes.get(&n).unwrap()).collect();
        output(real_nodes, i);
    }
}

/// Serializes the contents of the component into a stream where each node is
/// separated by `delim`. Panics if target cannot be opened.
pub fn serialize<W>(comp: Vec<u64>, target: &mut BufWriter<W>, delim: u8) where W: Write {
    for node in comp {
        target.write(node.to_string().as_bytes()).unwrap();
        target.write(&[delim]).unwrap();
    }
}
<|endoftext|>


<commit_before>use rpn_calculator::*;
use CalculatorInput::*;

#[test]
fn test_empty_input_returns_none() {
    let input = vec![];
    assert_eq!(evaluate(&input), None);
}

#[test]
#[ignore]
fn test_simple_value() {
    let input = vec![Value(10)];
    assert_eq!(evaluate(&input), Some(10));
}

#[test]
#[ignore]
fn test_simple_addition() {
    let input = vec![Value(2), Value(2), Add];
    assert_eq!(evaluate(&input), Some(4));
}

#[test]
#[ignore]
fn test_simple_subtraction() {
    let input = vec![Value(7), Value(11), Subtract];
    assert_eq!(evaluate(&input), Some(-4));
}

#[test]
#[ignore]
fn test_simple_multiplication() {
    let input = vec![Value(6), Value(9), Multiply];
    assert_eq!(evaluate(&input), Some(54));
}

#[test]
#[ignore]
fn test_simple_division() {
    let input = vec![Value(57), Value(19), Divide];
    assert_eq!(evaluate(&input), Some(3));
}

#[test]
#[ignore]
fn test_complex_operation() {
    let input = vec![
        Value(4),
        Value(8),
        Add,
        Value(7),
        Value(5),
        Subtract,
        Divide,
    ];
    assert_eq!(evaluate(&input), Some(6));
}

#[test]
#[ignore]
fn test_too_few_operands_returns_none() {
    let input = vec![Value(2), Add];
    assert_eq!(evaluate(&input), None);
}

#[test]
#[ignore]
fn test_too_many_operands_returns_none() {
    let input = vec![Value(2), Value(2)];
    assert_eq!(evaluate(&input), None);
}
<commit_msg>Implement calculator_input in tests<commit_after>use rpn_calculator::*;

fn calculator_input(s: &str) -> Vec<CalculatorInput> {
    s.split_whitespace()
        .map(|s| match s {
            "+" => CalculatorInput::Add,
            "-" => CalculatorInput::Subtract,
            "*" => CalculatorInput::Multiply,
            "/" => CalculatorInput::Divide,
            n => CalculatorInput::Value(n.parse().unwrap()),
        })
        .collect()
}

#[test]
fn test_empty_input_returns_none() {
    let input = calculator_input("");
    assert_eq!(evaluate(&input), None);
}

#[test]
#[ignore]
fn test_simple_value() {
    let input = calculator_input("10");
    assert_eq!(evaluate(&input), Some(10));
}

#[test]
#[ignore]
fn test_simple_addition() {
    let input = calculator_input("2 2 +");
    assert_eq!(evaluate(&input), Some(4));
}

#[test]
#[ignore]
fn test_simple_subtraction() {
    let input = calculator_input("7 11 -");
    assert_eq!(evaluate(&input), Some(-4));
}

#[test]
#[ignore]
fn test_simple_multiplication() {
    let input = calculator_input("6 9 *");
    assert_eq!(evaluate(&input), Some(54));
}

#[test]
#[ignore]
fn test_simple_division() {
    let input = calculator_input("57 19 /");
    assert_eq!(evaluate(&input), Some(3));
}

#[test]
#[ignore]
fn test_complex_operation() {
    let input = calculator_input("4 8 + 7 5 - /");
    assert_eq!(evaluate(&input), Some(6));
}

#[test]
#[ignore]
fn test_too_few_operands_returns_none() {
    let input = calculator_input("2 +");
    assert_eq!(evaluate(&input), None);
}

#[test]
#[ignore]
fn test_too_many_operands_returns_none() {
    let input = calculator_input("2 2");
    assert_eq!(evaluate(&input), None);
}
<|endoftext|>


<commit_before>
#[macro_use] extern crate text_io;
//#[cfg(feature= "withcompiletest")]
pub fn main() {
    let a: i32;
    let b: &mut u8 = &mut 5;
    scan!("{", a, *b);//^^^~error 7:11: 7:16: invalid format string: expected '}' but string was terminated
}<commit_msg>add newline at eof and remove old comment<commit_after>
#[macro_use] extern crate text_io;
pub fn main() {
    let a: i32;
    let b: &mut u8 = &mut 5;
    scan!("{", a, *b);//^^^~error 7:11: 7:16: invalid format string: expected '}' but string was terminated
}
<|endoftext|>