xref: /libCEED/rust/libceed/src/vector.rs (revision e03682af89f4c0f5e8c281990d44146e81dbdd46)
19df49d7eSJed Brown // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
29df49d7eSJed Brown // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
39df49d7eSJed Brown // reserved. See files LICENSE and NOTICE for details.
49df49d7eSJed Brown //
59df49d7eSJed Brown // This file is part of CEED, a collection of benchmarks, miniapps, software
69df49d7eSJed Brown // libraries and APIs for efficient high-order finite element and spectral
79df49d7eSJed Brown // element discretizations for exascale applications. For more information and
89df49d7eSJed Brown // source code availability see http://github.com/ceed.
99df49d7eSJed Brown //
109df49d7eSJed Brown // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
119df49d7eSJed Brown // a collaborative effort of two U.S. Department of Energy organizations (Office
129df49d7eSJed Brown // of Science and the National Nuclear Security Administration) responsible for
139df49d7eSJed Brown // the planning and preparation of a capable exascale ecosystem, including
149df49d7eSJed Brown // software, applications, hardware, advanced system engineering and early
159df49d7eSJed Brown // testbed platforms, in support of the nation's exascale computing imperative
169df49d7eSJed Brown 
179df49d7eSJed Brown //! A Ceed Vector constitutes the main data structure and serves as input/output
189df49d7eSJed Brown //! for Ceed Operators.
199df49d7eSJed Brown 
209df49d7eSJed Brown use std::{
219df49d7eSJed Brown     ops::{Deref, DerefMut},
229df49d7eSJed Brown     os::raw::c_char,
239df49d7eSJed Brown };
249df49d7eSJed Brown 
259df49d7eSJed Brown use crate::prelude::*;
269df49d7eSJed Brown 
279df49d7eSJed Brown // -----------------------------------------------------------------------------
289df49d7eSJed Brown // CeedVector option
299df49d7eSJed Brown // -----------------------------------------------------------------------------
30c68be7a2SJeremy L Thompson #[derive(Debug)]
319df49d7eSJed Brown pub enum VectorOpt<'a> {
329df49d7eSJed Brown     Some(&'a Vector<'a>),
339df49d7eSJed Brown     Active,
349df49d7eSJed Brown     None,
359df49d7eSJed Brown }
369df49d7eSJed Brown /// Construct a VectorOpt reference from a Vector reference
379df49d7eSJed Brown impl<'a> From<&'a Vector<'_>> for VectorOpt<'a> {
389df49d7eSJed Brown     fn from(vec: &'a Vector) -> Self {
399df49d7eSJed Brown         debug_assert!(vec.ptr != unsafe { bind_ceed::CEED_VECTOR_ACTIVE });
40c68be7a2SJeremy L Thompson         debug_assert!(vec.ptr != unsafe { bind_ceed::CEED_VECTOR_NONE });
419df49d7eSJed Brown         Self::Some(vec)
429df49d7eSJed Brown     }
439df49d7eSJed Brown }
449df49d7eSJed Brown impl<'a> VectorOpt<'a> {
459df49d7eSJed Brown     /// Transform a Rust libCEED VectorOpt into C libCEED CeedVector
469df49d7eSJed Brown     pub(crate) fn to_raw(self) -> bind_ceed::CeedVector {
479df49d7eSJed Brown         match self {
489df49d7eSJed Brown             Self::Some(vec) => vec.ptr,
499df49d7eSJed Brown             Self::Active => unsafe { bind_ceed::CEED_VECTOR_ACTIVE },
50c68be7a2SJeremy L Thompson             Self::None => unsafe { bind_ceed::CEED_VECTOR_NONE },
519df49d7eSJed Brown         }
529df49d7eSJed Brown     }
53*e03682afSJeremy L Thompson 
54*e03682afSJeremy L Thompson     /// Check if a VectorOpt is Some
55*e03682afSJeremy L Thompson     ///
56*e03682afSJeremy L Thompson     /// ```
57*e03682afSJeremy L Thompson     /// # use libceed::prelude::*;
58*e03682afSJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
59*e03682afSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
60*e03682afSJeremy L Thompson     /// let vec = libceed::vector::Vector::from_slice(&ceed, &[1., 2., 3.])?;
61*e03682afSJeremy L Thompson     /// let vec_opt = VectorOpt::from(&vec);
62*e03682afSJeremy L Thompson     /// assert!(vec_opt.is_some(), "Incorrect VectorOpt");
63*e03682afSJeremy L Thompson     ///
64*e03682afSJeremy L Thompson     /// let vec_opt = VectorOpt::Active;
65*e03682afSJeremy L Thompson     /// assert!(!vec_opt.is_some(), "Incorrect VectorOpt");
66*e03682afSJeremy L Thompson     ///
67*e03682afSJeremy L Thompson     /// let vec_opt = VectorOpt::None;
68*e03682afSJeremy L Thompson     /// assert!(!vec_opt.is_some(), "Incorrect VectorOpt");
69*e03682afSJeremy L Thompson     /// # Ok(())
70*e03682afSJeremy L Thompson     /// # }
71*e03682afSJeremy L Thompson     /// ```
72*e03682afSJeremy L Thompson     pub fn is_some(&self) -> bool {
73*e03682afSJeremy L Thompson         match self {
74*e03682afSJeremy L Thompson             Self::Some(_) => true,
75*e03682afSJeremy L Thompson             Self::Active => false,
76*e03682afSJeremy L Thompson             Self::None => false,
77*e03682afSJeremy L Thompson         }
78*e03682afSJeremy L Thompson     }
79*e03682afSJeremy L Thompson 
80*e03682afSJeremy L Thompson     /// Check if a VectorOpt is Active
81*e03682afSJeremy L Thompson     ///
82*e03682afSJeremy L Thompson     /// ```
83*e03682afSJeremy L Thompson     /// # use libceed::prelude::*;
84*e03682afSJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
85*e03682afSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
86*e03682afSJeremy L Thompson     /// let vec = libceed::vector::Vector::from_slice(&ceed, &[1., 2., 3.])?;
87*e03682afSJeremy L Thompson     /// let vec_opt = VectorOpt::from(&vec);
88*e03682afSJeremy L Thompson     /// assert!(!vec_opt.is_active(), "Incorrect VectorOpt");
89*e03682afSJeremy L Thompson     ///
90*e03682afSJeremy L Thompson     /// let vec_opt = VectorOpt::Active;
91*e03682afSJeremy L Thompson     /// assert!(vec_opt.is_active(), "Incorrect VectorOpt");
92*e03682afSJeremy L Thompson     ///
93*e03682afSJeremy L Thompson     /// let vec_opt = VectorOpt::None;
94*e03682afSJeremy L Thompson     /// assert!(!vec_opt.is_active(), "Incorrect VectorOpt");
95*e03682afSJeremy L Thompson     /// # Ok(())
96*e03682afSJeremy L Thompson     /// # }
97*e03682afSJeremy L Thompson     /// ```
98*e03682afSJeremy L Thompson     pub fn is_active(&self) -> bool {
99*e03682afSJeremy L Thompson         match self {
100*e03682afSJeremy L Thompson             Self::Some(_) => false,
101*e03682afSJeremy L Thompson             Self::Active => true,
102*e03682afSJeremy L Thompson             Self::None => false,
103*e03682afSJeremy L Thompson         }
104*e03682afSJeremy L Thompson     }
105*e03682afSJeremy L Thompson 
106*e03682afSJeremy L Thompson     /// Check if a VectorOpt is Some
107*e03682afSJeremy L Thompson     ///
108*e03682afSJeremy L Thompson     /// ```
109*e03682afSJeremy L Thompson     /// # use libceed::prelude::*;
110*e03682afSJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
111*e03682afSJeremy L Thompson     /// # let ceed = libceed::Ceed::default_init();
112*e03682afSJeremy L Thompson     /// let vec = libceed::vector::Vector::from_slice(&ceed, &[1., 2., 3.])?;
113*e03682afSJeremy L Thompson     /// let vec_opt = VectorOpt::from(&vec);
114*e03682afSJeremy L Thompson     /// assert!(!vec_opt.is_none(), "Incorrect VectorOpt");
115*e03682afSJeremy L Thompson     ///
116*e03682afSJeremy L Thompson     /// let vec_opt = VectorOpt::Active;
117*e03682afSJeremy L Thompson     /// assert!(!vec_opt.is_none(), "Incorrect VectorOpt");
118*e03682afSJeremy L Thompson     ///
119*e03682afSJeremy L Thompson     /// let vec_opt = VectorOpt::None;
120*e03682afSJeremy L Thompson     /// assert!(vec_opt.is_none(), "Incorrect VectorOpt");
121*e03682afSJeremy L Thompson     /// # Ok(())
122*e03682afSJeremy L Thompson     /// # }
123*e03682afSJeremy L Thompson     /// ```
124*e03682afSJeremy L Thompson     pub fn is_none(&self) -> bool {
125*e03682afSJeremy L Thompson         match self {
126*e03682afSJeremy L Thompson             Self::Some(_) => false,
127*e03682afSJeremy L Thompson             Self::Active => false,
128*e03682afSJeremy L Thompson             Self::None => true,
129*e03682afSJeremy L Thompson         }
130*e03682afSJeremy L Thompson     }
1319df49d7eSJed Brown }
1329df49d7eSJed Brown 
1339df49d7eSJed Brown // -----------------------------------------------------------------------------
1349df49d7eSJed Brown // CeedVector context wrapper
1359df49d7eSJed Brown // -----------------------------------------------------------------------------
1369df49d7eSJed Brown #[derive(Debug)]
1379df49d7eSJed Brown pub struct Vector<'a> {
1389df49d7eSJed Brown     ceed: &'a crate::Ceed,
1399df49d7eSJed Brown     pub(crate) ptr: bind_ceed::CeedVector,
1409df49d7eSJed Brown }
1419df49d7eSJed Brown impl From<&'_ Vector<'_>> for bind_ceed::CeedVector {
1429df49d7eSJed Brown     fn from(vec: &Vector) -> Self {
1439df49d7eSJed Brown         vec.ptr
1449df49d7eSJed Brown     }
1459df49d7eSJed Brown }
1469df49d7eSJed Brown 
1479df49d7eSJed Brown // -----------------------------------------------------------------------------
1489df49d7eSJed Brown // Destructor
1499df49d7eSJed Brown // -----------------------------------------------------------------------------
1509df49d7eSJed Brown impl<'a> Drop for Vector<'a> {
1519df49d7eSJed Brown     fn drop(&mut self) {
1529df49d7eSJed Brown         let not_none_and_active = self.ptr != unsafe { bind_ceed::CEED_VECTOR_NONE }
1539df49d7eSJed Brown             && self.ptr != unsafe { bind_ceed::CEED_VECTOR_ACTIVE };
1549df49d7eSJed Brown 
1559df49d7eSJed Brown         if not_none_and_active {
1569df49d7eSJed Brown             unsafe { bind_ceed::CeedVectorDestroy(&mut self.ptr) };
1579df49d7eSJed Brown         }
1589df49d7eSJed Brown     }
1599df49d7eSJed Brown }
1609df49d7eSJed Brown 
1619df49d7eSJed Brown // -----------------------------------------------------------------------------
1629df49d7eSJed Brown // Display
1639df49d7eSJed Brown // -----------------------------------------------------------------------------
1649df49d7eSJed Brown impl<'a> fmt::Display for Vector<'a> {
1659df49d7eSJed Brown     /// View a Vector
1669df49d7eSJed Brown     ///
1679df49d7eSJed Brown     /// ```
1689df49d7eSJed Brown     /// # use libceed::prelude::*;
169c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
1709df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
171c68be7a2SJeremy L Thompson     /// let vec = libceed::vector::Vector::from_slice(&ceed, &[1., 2., 3.])?;
1729df49d7eSJed Brown     /// assert_eq!(
1739df49d7eSJed Brown     ///     vec.to_string(),
1749df49d7eSJed Brown     ///     "CeedVector length 3
1759df49d7eSJed Brown     ///     1.00000000
1769df49d7eSJed Brown     ///     2.00000000
1779df49d7eSJed Brown     ///     3.00000000
1789df49d7eSJed Brown     /// "
179c68be7a2SJeremy L Thompson     /// );
180c68be7a2SJeremy L Thompson     /// # Ok(())
181c68be7a2SJeremy L Thompson     /// # }
1829df49d7eSJed Brown     /// ```
1839df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1849df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
1859df49d7eSJed Brown         let mut sizeloc = crate::MAX_BUFFER_LENGTH;
1869df49d7eSJed Brown         let format = CString::new("%12.8f").expect("CString::new failed");
1879df49d7eSJed Brown         let format_c: *const c_char = format.into_raw();
1889df49d7eSJed Brown         let cstring = unsafe {
1899df49d7eSJed Brown             let file = bind_ceed::open_memstream(&mut ptr, &mut sizeloc);
1909df49d7eSJed Brown             bind_ceed::CeedVectorView(self.ptr, format_c, file);
1919df49d7eSJed Brown             bind_ceed::fclose(file);
1929df49d7eSJed Brown             CString::from_raw(ptr)
1939df49d7eSJed Brown         };
1949df49d7eSJed Brown         cstring.to_string_lossy().fmt(f)
1959df49d7eSJed Brown     }
1969df49d7eSJed Brown }
1979df49d7eSJed Brown 
1989df49d7eSJed Brown // -----------------------------------------------------------------------------
1999df49d7eSJed Brown // Implementations
2009df49d7eSJed Brown // -----------------------------------------------------------------------------
2019df49d7eSJed Brown impl<'a> Vector<'a> {
2029df49d7eSJed Brown     // Constructors
2039df49d7eSJed Brown     pub fn create(ceed: &'a crate::Ceed, n: usize) -> crate::Result<Self> {
2049df49d7eSJed Brown         let n = i32::try_from(n).unwrap();
2059df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
2069df49d7eSJed Brown         let ierr = unsafe { bind_ceed::CeedVectorCreate(ceed.ptr, n, &mut ptr) };
2079df49d7eSJed Brown         ceed.check_error(ierr)?;
2089df49d7eSJed Brown         Ok(Self { ceed, ptr })
2099df49d7eSJed Brown     }
2109df49d7eSJed Brown 
2119df49d7eSJed Brown     pub(crate) fn from_raw(
2129df49d7eSJed Brown         ceed: &'a crate::Ceed,
2139df49d7eSJed Brown         ptr: bind_ceed::CeedVector,
2149df49d7eSJed Brown     ) -> crate::Result<Self> {
2159df49d7eSJed Brown         Ok(Self { ceed, ptr })
2169df49d7eSJed Brown     }
2179df49d7eSJed Brown 
2189df49d7eSJed Brown     /// Create a Vector from a slice
2199df49d7eSJed Brown     ///
2209df49d7eSJed Brown     /// # arguments
2219df49d7eSJed Brown     ///
2229df49d7eSJed Brown     /// * `slice` - values to initialize vector with
2239df49d7eSJed Brown     ///
2249df49d7eSJed Brown     /// ```
2259df49d7eSJed Brown     /// # use libceed::prelude::*;
226c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
2279df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
228c68be7a2SJeremy L Thompson     /// let vec = vector::Vector::from_slice(&ceed, &[1., 2., 3.])?;
2299df49d7eSJed Brown     /// assert_eq!(vec.length(), 3, "Incorrect length from slice");
230c68be7a2SJeremy L Thompson     /// # Ok(())
231c68be7a2SJeremy L Thompson     /// # }
2329df49d7eSJed Brown     /// ```
23380a9ef05SNatalie Beams     pub fn from_slice(ceed: &'a crate::Ceed, v: &[crate::Scalar]) -> crate::Result<Self> {
2349df49d7eSJed Brown         let mut x = Self::create(ceed, v.len())?;
2359df49d7eSJed Brown         x.set_slice(v)?;
2369df49d7eSJed Brown         Ok(x)
2379df49d7eSJed Brown     }
2389df49d7eSJed Brown 
2399df49d7eSJed Brown     /// Create a Vector from a mutable array reference
2409df49d7eSJed Brown     ///
2419df49d7eSJed Brown     /// # arguments
2429df49d7eSJed Brown     ///
2439df49d7eSJed Brown     /// * `slice` - values to initialize vector with
2449df49d7eSJed Brown     ///
2459df49d7eSJed Brown     /// ```
2469df49d7eSJed Brown     /// # use libceed::prelude::*;
247c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
2489df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
2499df49d7eSJed Brown     /// let mut rust_vec = vec![1., 2., 3.];
250c68be7a2SJeremy L Thompson     /// let vec = libceed::vector::Vector::from_array(&ceed, &mut rust_vec)?;
2519df49d7eSJed Brown     ///
2529df49d7eSJed Brown     /// assert_eq!(vec.length(), 3, "Incorrect length from slice");
253c68be7a2SJeremy L Thompson     /// # Ok(())
254c68be7a2SJeremy L Thompson     /// # }
2559df49d7eSJed Brown     /// ```
25680a9ef05SNatalie Beams     pub fn from_array(ceed: &'a crate::Ceed, v: &mut [crate::Scalar]) -> crate::Result<Self> {
2579df49d7eSJed Brown         let x = Self::create(ceed, v.len())?;
2589df49d7eSJed Brown         let (host, user_pointer) = (
2599df49d7eSJed Brown             crate::MemType::Host as bind_ceed::CeedMemType,
2609df49d7eSJed Brown             crate::CopyMode::UsePointer as bind_ceed::CeedCopyMode,
2619df49d7eSJed Brown         );
26280a9ef05SNatalie Beams         let v = v.as_ptr() as *mut crate::Scalar;
2639df49d7eSJed Brown         let ierr = unsafe { bind_ceed::CeedVectorSetArray(x.ptr, host, user_pointer, v) };
2649df49d7eSJed Brown         ceed.check_error(ierr)?;
2659df49d7eSJed Brown         Ok(x)
2669df49d7eSJed Brown     }
2679df49d7eSJed Brown 
2689df49d7eSJed Brown     /// Returns the length of a CeedVector
2699df49d7eSJed Brown     ///
2709df49d7eSJed Brown     /// ```
2719df49d7eSJed Brown     /// # use libceed::prelude::*;
272c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
2739df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
274c68be7a2SJeremy L Thompson     /// let vec = ceed.vector(10)?;
2759df49d7eSJed Brown     ///
2769df49d7eSJed Brown     /// let n = vec.length();
2779df49d7eSJed Brown     /// assert_eq!(n, 10, "Incorrect length");
278c68be7a2SJeremy L Thompson     /// # Ok(())
279c68be7a2SJeremy L Thompson     /// # }
2809df49d7eSJed Brown     /// ```
2819df49d7eSJed Brown     pub fn length(&self) -> usize {
2829df49d7eSJed Brown         let mut n = 0;
2839df49d7eSJed Brown         unsafe { bind_ceed::CeedVectorGetLength(self.ptr, &mut n) };
2849df49d7eSJed Brown         usize::try_from(n).unwrap()
2859df49d7eSJed Brown     }
2869df49d7eSJed Brown 
2879df49d7eSJed Brown     /// Returns the length of a CeedVector
2889df49d7eSJed Brown     ///
2899df49d7eSJed Brown     /// ```
2909df49d7eSJed Brown     /// # use libceed::prelude::*;
291c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
2929df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
293c68be7a2SJeremy L Thompson     /// let vec = ceed.vector(10)?;
2949df49d7eSJed Brown     /// assert_eq!(vec.len(), 10, "Incorrect length");
295c68be7a2SJeremy L Thompson     /// # Ok(())
296c68be7a2SJeremy L Thompson     /// # }
2979df49d7eSJed Brown     /// ```
2989df49d7eSJed Brown     pub fn len(&self) -> usize {
2999df49d7eSJed Brown         self.length()
3009df49d7eSJed Brown     }
3019df49d7eSJed Brown 
3029df49d7eSJed Brown     /// Set the CeedVector to a constant value
3039df49d7eSJed Brown     ///
3049df49d7eSJed Brown     /// # arguments
3059df49d7eSJed Brown     ///
3069df49d7eSJed Brown     /// * `val` - Value to be used
3079df49d7eSJed Brown     ///
3089df49d7eSJed Brown     /// ```
3099df49d7eSJed Brown     /// # use libceed::prelude::*;
310c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
3119df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
3129df49d7eSJed Brown     /// let len = 10;
313c68be7a2SJeremy L Thompson     /// let mut vec = ceed.vector(len)?;
3149df49d7eSJed Brown     ///
3159df49d7eSJed Brown     /// let val = 42.0;
316c68be7a2SJeremy L Thompson     /// vec.set_value(val)?;
3179df49d7eSJed Brown     ///
3189df49d7eSJed Brown     /// vec.view().iter().for_each(|v| {
3199df49d7eSJed Brown     ///     assert_eq!(*v, val, "Value not set correctly");
3209df49d7eSJed Brown     /// });
321c68be7a2SJeremy L Thompson     /// # Ok(())
322c68be7a2SJeremy L Thompson     /// # }
3239df49d7eSJed Brown     /// ```
32480a9ef05SNatalie Beams     pub fn set_value(&mut self, value: crate::Scalar) -> crate::Result<i32> {
3259df49d7eSJed Brown         let ierr = unsafe { bind_ceed::CeedVectorSetValue(self.ptr, value) };
3269df49d7eSJed Brown         self.ceed.check_error(ierr)
3279df49d7eSJed Brown     }
3289df49d7eSJed Brown 
3299df49d7eSJed Brown     /// Set values from a slice of the same length
3309df49d7eSJed Brown     ///
3319df49d7eSJed Brown     /// # arguments
3329df49d7eSJed Brown     ///
3339df49d7eSJed Brown     /// * `slice` - values to into self; length must match
3349df49d7eSJed Brown     ///
3359df49d7eSJed Brown     /// ```
3369df49d7eSJed Brown     /// # use libceed::prelude::*;
337c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
3389df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
339c68be7a2SJeremy L Thompson     /// let mut vec = ceed.vector(4)?;
340c68be7a2SJeremy L Thompson     /// vec.set_slice(&[10., 11., 12., 13.])?;
3419df49d7eSJed Brown     ///
3429df49d7eSJed Brown     /// vec.view().iter().enumerate().for_each(|(i, v)| {
34380a9ef05SNatalie Beams     ///     assert_eq!(*v, 10. + i as Scalar, "Slice not set correctly");
3449df49d7eSJed Brown     /// });
345c68be7a2SJeremy L Thompson     /// # Ok(())
346c68be7a2SJeremy L Thompson     /// # }
3479df49d7eSJed Brown     /// ```
34880a9ef05SNatalie Beams     pub fn set_slice(&mut self, slice: &[crate::Scalar]) -> crate::Result<i32> {
3499df49d7eSJed Brown         assert_eq!(self.length(), slice.len());
3509df49d7eSJed Brown         let (host, copy_mode) = (
3519df49d7eSJed Brown             crate::MemType::Host as bind_ceed::CeedMemType,
3529df49d7eSJed Brown             crate::CopyMode::CopyValues as bind_ceed::CeedCopyMode,
3539df49d7eSJed Brown         );
3549df49d7eSJed Brown         let ierr = unsafe {
35580a9ef05SNatalie Beams             bind_ceed::CeedVectorSetArray(
35680a9ef05SNatalie Beams                 self.ptr,
35780a9ef05SNatalie Beams                 host,
35880a9ef05SNatalie Beams                 copy_mode,
35980a9ef05SNatalie Beams                 slice.as_ptr() as *mut crate::Scalar,
36080a9ef05SNatalie Beams             )
3619df49d7eSJed Brown         };
3629df49d7eSJed Brown         self.ceed.check_error(ierr)
3639df49d7eSJed Brown     }
3649df49d7eSJed Brown 
3659df49d7eSJed Brown     /// Sync the CeedVector to a specified memtype
3669df49d7eSJed Brown     ///
3679df49d7eSJed Brown     /// # arguments
3689df49d7eSJed Brown     ///
3699df49d7eSJed Brown     /// * `mtype` - Memtype to be synced
3709df49d7eSJed Brown     ///
3719df49d7eSJed Brown     /// ```
3729df49d7eSJed Brown     /// # use libceed::prelude::*;
373c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
3749df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
3759df49d7eSJed Brown     /// let len = 10;
376c68be7a2SJeremy L Thompson     /// let mut vec = ceed.vector(len)?;
3779df49d7eSJed Brown     ///
3789df49d7eSJed Brown     /// let val = 42.0;
3799df49d7eSJed Brown     /// vec.set_value(val);
380c68be7a2SJeremy L Thompson     /// vec.sync(MemType::Host)?;
3819df49d7eSJed Brown     ///
3829df49d7eSJed Brown     /// vec.view().iter().for_each(|v| {
3839df49d7eSJed Brown     ///     assert_eq!(*v, val, "Value not set correctly");
3849df49d7eSJed Brown     /// });
385c68be7a2SJeremy L Thompson     /// # Ok(())
386c68be7a2SJeremy L Thompson     /// # }
3879df49d7eSJed Brown     /// ```
3889df49d7eSJed Brown     pub fn sync(&self, mtype: crate::MemType) -> crate::Result<i32> {
3899df49d7eSJed Brown         let ierr =
3909df49d7eSJed Brown             unsafe { bind_ceed::CeedVectorSyncArray(self.ptr, mtype as bind_ceed::CeedMemType) };
3919df49d7eSJed Brown         self.ceed.check_error(ierr)
3929df49d7eSJed Brown     }
3939df49d7eSJed Brown 
3949df49d7eSJed Brown     /// Create an immutable view
3959df49d7eSJed Brown     ///
3969df49d7eSJed Brown     /// ```
3979df49d7eSJed Brown     /// # use libceed::prelude::*;
398c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
3999df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
400c68be7a2SJeremy L Thompson     /// let vec = ceed.vector_from_slice(&[10., 11., 12., 13.])?;
4019df49d7eSJed Brown     ///
4029df49d7eSJed Brown     /// let v = vec.view();
4039df49d7eSJed Brown     /// assert_eq!(v[0..2], [10., 11.]);
4049df49d7eSJed Brown     ///
4059df49d7eSJed Brown     /// // It is valid to have multiple immutable views
4069df49d7eSJed Brown     /// let w = vec.view();
4079df49d7eSJed Brown     /// assert_eq!(v[1..], w[1..]);
408c68be7a2SJeremy L Thompson     /// # Ok(())
409c68be7a2SJeremy L Thompson     /// # }
4109df49d7eSJed Brown     /// ```
4119df49d7eSJed Brown     pub fn view(&self) -> VectorView {
4129df49d7eSJed Brown         VectorView::new(self)
4139df49d7eSJed Brown     }
4149df49d7eSJed Brown 
4159df49d7eSJed Brown     /// Create an mutable view
4169df49d7eSJed Brown     ///
4179df49d7eSJed Brown     /// ```
4189df49d7eSJed Brown     /// # use libceed::prelude::*;
419c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
4209df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
421c68be7a2SJeremy L Thompson     /// let mut vec = ceed.vector_from_slice(&[10., 11., 12., 13.])?;
4229df49d7eSJed Brown     ///
4239df49d7eSJed Brown     /// {
4249df49d7eSJed Brown     ///     let mut v = vec.view_mut();
4259df49d7eSJed Brown     ///     v[2] = 9.;
4269df49d7eSJed Brown     /// }
4279df49d7eSJed Brown     ///
4289df49d7eSJed Brown     /// let w = vec.view();
4299df49d7eSJed Brown     /// assert_eq!(w[2], 9., "View did not mutate data");
430c68be7a2SJeremy L Thompson     /// # Ok(())
431c68be7a2SJeremy L Thompson     /// # }
4329df49d7eSJed Brown     /// ```
4339df49d7eSJed Brown     pub fn view_mut(&mut self) -> VectorViewMut {
4349df49d7eSJed Brown         VectorViewMut::new(self)
4359df49d7eSJed Brown     }
4369df49d7eSJed Brown 
4379df49d7eSJed Brown     /// Return the norm of a CeedVector
4389df49d7eSJed Brown     ///
4399df49d7eSJed Brown     /// # arguments
4409df49d7eSJed Brown     ///
4419df49d7eSJed Brown     /// * `ntype` - Norm type One, Two, or Max
4429df49d7eSJed Brown     ///
4439df49d7eSJed Brown     /// ```
4449df49d7eSJed Brown     /// # use libceed::prelude::*;
445c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
4469df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
447c68be7a2SJeremy L Thompson     /// let vec = ceed.vector_from_slice(&[1., 2., 3., 4.])?;
4489df49d7eSJed Brown     ///
449c68be7a2SJeremy L Thompson     /// let max_norm = vec.norm(NormType::Max)?;
4509df49d7eSJed Brown     /// assert_eq!(max_norm, 4.0, "Incorrect Max norm");
4519df49d7eSJed Brown     ///
452c68be7a2SJeremy L Thompson     /// let l1_norm = vec.norm(NormType::One)?;
4539df49d7eSJed Brown     /// assert_eq!(l1_norm, 10., "Incorrect L1 norm");
4549df49d7eSJed Brown     ///
455c68be7a2SJeremy L Thompson     /// let l2_norm = vec.norm(NormType::Two)?;
4569df49d7eSJed Brown     /// assert!((l2_norm - 5.477) < 1e-3, "Incorrect L2 norm");
457c68be7a2SJeremy L Thompson     /// # Ok(())
458c68be7a2SJeremy L Thompson     /// # }
4599df49d7eSJed Brown     /// ```
46080a9ef05SNatalie Beams     pub fn norm(&self, ntype: crate::NormType) -> crate::Result<crate::Scalar> {
46180a9ef05SNatalie Beams         let mut res: crate::Scalar = 0.0;
4629df49d7eSJed Brown         let ierr = unsafe {
4639df49d7eSJed Brown             bind_ceed::CeedVectorNorm(self.ptr, ntype as bind_ceed::CeedNormType, &mut res)
4649df49d7eSJed Brown         };
4659df49d7eSJed Brown         self.ceed.check_error(ierr)?;
4669df49d7eSJed Brown         Ok(res)
4679df49d7eSJed Brown     }
4689df49d7eSJed Brown 
4699df49d7eSJed Brown     /// Compute x = alpha x for a CeedVector
4709df49d7eSJed Brown     ///
4719df49d7eSJed Brown     /// # arguments
4729df49d7eSJed Brown     ///
4739df49d7eSJed Brown     /// * `alpha` - scaling factor
4749df49d7eSJed Brown     ///
4759df49d7eSJed Brown     /// ```
4769df49d7eSJed Brown     /// # use libceed::prelude::*;
477c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
4789df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
479c68be7a2SJeremy L Thompson     /// let mut vec = ceed.vector_from_slice(&[0., 1., 2., 3., 4.])?;
4809df49d7eSJed Brown     ///
481c68be7a2SJeremy L Thompson     /// vec = vec.scale(-1.0)?;
4829df49d7eSJed Brown     /// vec.view().iter().enumerate().for_each(|(i, &v)| {
48380a9ef05SNatalie Beams     ///     assert_eq!(v, -(i as Scalar), "Value not set correctly");
4849df49d7eSJed Brown     /// });
485c68be7a2SJeremy L Thompson     /// # Ok(())
486c68be7a2SJeremy L Thompson     /// # }
4879df49d7eSJed Brown     /// ```
4889df49d7eSJed Brown     #[allow(unused_mut)]
48980a9ef05SNatalie Beams     pub fn scale(mut self, alpha: crate::Scalar) -> crate::Result<Self> {
4909df49d7eSJed Brown         let ierr = unsafe { bind_ceed::CeedVectorScale(self.ptr, alpha) };
4919df49d7eSJed Brown         self.ceed.check_error(ierr)?;
4929df49d7eSJed Brown         Ok(self)
4939df49d7eSJed Brown     }
4949df49d7eSJed Brown 
4959df49d7eSJed Brown     /// Compute y = alpha x + y for a pair of CeedVectors
4969df49d7eSJed Brown     ///
4979df49d7eSJed Brown     /// # arguments
4989df49d7eSJed Brown     ///
4999df49d7eSJed Brown     /// * `alpha` - scaling factor
5009df49d7eSJed Brown     /// * `x`     - second vector, must be different than self
5019df49d7eSJed Brown     ///
5029df49d7eSJed Brown     /// ```
5039df49d7eSJed Brown     /// # use libceed::prelude::*;
504c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
5059df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
506c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[0., 1., 2., 3., 4.])?;
507c68be7a2SJeremy L Thompson     /// let mut y = ceed.vector_from_slice(&[0., 1., 2., 3., 4.])?;
5089df49d7eSJed Brown     ///
509c68be7a2SJeremy L Thompson     /// y = y.axpy(-0.5, &x)?;
5109df49d7eSJed Brown     /// y.view().iter().enumerate().for_each(|(i, &v)| {
51180a9ef05SNatalie Beams     ///     assert_eq!(v, (i as Scalar) / 2.0, "Value not set correctly");
5129df49d7eSJed Brown     /// });
513c68be7a2SJeremy L Thompson     /// # Ok(())
514c68be7a2SJeremy L Thompson     /// # }
5159df49d7eSJed Brown     /// ```
5169df49d7eSJed Brown     #[allow(unused_mut)]
51780a9ef05SNatalie Beams     pub fn axpy(mut self, alpha: crate::Scalar, x: &crate::Vector) -> crate::Result<Self> {
5189df49d7eSJed Brown         let ierr = unsafe { bind_ceed::CeedVectorAXPY(self.ptr, alpha, x.ptr) };
5199df49d7eSJed Brown         self.ceed.check_error(ierr)?;
5209df49d7eSJed Brown         Ok(self)
5219df49d7eSJed Brown     }
5229df49d7eSJed Brown 
5239df49d7eSJed Brown     /// Compute the pointwise multiplication w = x .* y for CeedVectors
5249df49d7eSJed Brown     ///
5259df49d7eSJed Brown     /// # arguments
5269df49d7eSJed Brown     ///
5279df49d7eSJed Brown     /// * `x` - first vector for product
5289df49d7eSJed Brown     /// * `y` - second vector for product
5299df49d7eSJed Brown     ///
5309df49d7eSJed Brown     /// ```
5319df49d7eSJed Brown     /// # use libceed::prelude::*;
532c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
5339df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
534c68be7a2SJeremy L Thompson     /// let mut w = ceed.vector_from_slice(&[0., 1., 2., 3., 4.])?;
535c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[0., 1., 2., 3., 4.])?;
536c68be7a2SJeremy L Thompson     /// let y = ceed.vector_from_slice(&[0., 1., 2., 3., 4.])?;
5379df49d7eSJed Brown     ///
538c68be7a2SJeremy L Thompson     /// w = w.pointwise_mult(&x, &y)?;
5399df49d7eSJed Brown     /// w.view().iter().enumerate().for_each(|(i, &v)| {
54080a9ef05SNatalie Beams     ///     assert_eq!(v, (i as Scalar).powf(2.0), "Value not set correctly");
5419df49d7eSJed Brown     /// });
542c68be7a2SJeremy L Thompson     /// # Ok(())
543c68be7a2SJeremy L Thompson     /// # }
5449df49d7eSJed Brown     /// ```
5459df49d7eSJed Brown     #[allow(unused_mut)]
5469df49d7eSJed Brown     pub fn pointwise_mult(mut self, x: &crate::Vector, y: &crate::Vector) -> crate::Result<Self> {
5479df49d7eSJed Brown         let ierr = unsafe { bind_ceed::CeedVectorPointwiseMult(self.ptr, x.ptr, y.ptr) };
5489df49d7eSJed Brown         self.ceed.check_error(ierr)?;
5499df49d7eSJed Brown         Ok(self)
5509df49d7eSJed Brown     }
5519df49d7eSJed Brown 
5529df49d7eSJed Brown     /// Compute the pointwise multiplication w = w .* x for CeedVectors
5539df49d7eSJed Brown     ///
5549df49d7eSJed Brown     /// # arguments
5559df49d7eSJed Brown     ///
5569df49d7eSJed Brown     /// * `x` - second vector for product
5579df49d7eSJed Brown     ///
5589df49d7eSJed Brown     /// ```
5599df49d7eSJed Brown     /// # use libceed::prelude::*;
560c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
5619df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
562c68be7a2SJeremy L Thompson     /// let mut w = ceed.vector_from_slice(&[0., 1., 2., 3., 4.])?;
563c68be7a2SJeremy L Thompson     /// let x = ceed.vector_from_slice(&[0., 1., 2., 3., 4.])?;
5649df49d7eSJed Brown     ///
565c68be7a2SJeremy L Thompson     /// w = w.pointwise_scale(&x)?;
5669df49d7eSJed Brown     /// w.view().iter().enumerate().for_each(|(i, &v)| {
56780a9ef05SNatalie Beams     ///     assert_eq!(v, (i as Scalar).powf(2.0), "Value not set correctly");
5689df49d7eSJed Brown     /// });
569c68be7a2SJeremy L Thompson     /// # Ok(())
570c68be7a2SJeremy L Thompson     /// # }
5719df49d7eSJed Brown     /// ```
5729df49d7eSJed Brown     #[allow(unused_mut)]
5739df49d7eSJed Brown     pub fn pointwise_scale(mut self, x: &crate::Vector) -> crate::Result<Self> {
5749df49d7eSJed Brown         let ierr = unsafe { bind_ceed::CeedVectorPointwiseMult(self.ptr, self.ptr, x.ptr) };
5759df49d7eSJed Brown         self.ceed.check_error(ierr)?;
5769df49d7eSJed Brown         Ok(self)
5779df49d7eSJed Brown     }
5789df49d7eSJed Brown 
5799df49d7eSJed Brown     /// Compute the pointwise multiplication w = w .* w for a CeedVector
5809df49d7eSJed Brown     ///
5819df49d7eSJed Brown     /// ```
5829df49d7eSJed Brown     /// # use libceed::prelude::*;
583c68be7a2SJeremy L Thompson     /// # fn main() -> Result<(), libceed::CeedError> {
5849df49d7eSJed Brown     /// # let ceed = libceed::Ceed::default_init();
585c68be7a2SJeremy L Thompson     /// let mut w = ceed.vector_from_slice(&[0., 1., 2., 3., 4.])?;
5869df49d7eSJed Brown     ///
587c68be7a2SJeremy L Thompson     /// w = w.pointwise_square()?;
5889df49d7eSJed Brown     /// w.view().iter().enumerate().for_each(|(i, &v)| {
58980a9ef05SNatalie Beams     ///     assert_eq!(v, (i as Scalar).powf(2.0), "Value not set correctly");
5909df49d7eSJed Brown     /// });
591c68be7a2SJeremy L Thompson     /// # Ok(())
592c68be7a2SJeremy L Thompson     /// # }
5939df49d7eSJed Brown     /// ```
5949df49d7eSJed Brown     #[allow(unused_mut)]
5959df49d7eSJed Brown     pub fn pointwise_square(mut self) -> crate::Result<Self> {
5969df49d7eSJed Brown         let ierr = unsafe { bind_ceed::CeedVectorPointwiseMult(self.ptr, self.ptr, self.ptr) };
5979df49d7eSJed Brown         self.ceed.check_error(ierr)?;
5989df49d7eSJed Brown         Ok(self)
5999df49d7eSJed Brown     }
6009df49d7eSJed Brown }
6019df49d7eSJed Brown 
6029df49d7eSJed Brown // -----------------------------------------------------------------------------
6039df49d7eSJed Brown // Vector Viewer
6049df49d7eSJed Brown // -----------------------------------------------------------------------------
6059df49d7eSJed Brown /// A (host) view of a Vector with Deref to slice.  We can't make
6069df49d7eSJed Brown /// Vector itself Deref to slice because we can't handle the drop to
6079df49d7eSJed Brown /// call bind_ceed::CeedVectorRestoreArrayRead().
6089df49d7eSJed Brown #[derive(Debug)]
6099df49d7eSJed Brown pub struct VectorView<'a> {
6109df49d7eSJed Brown     vec: &'a Vector<'a>,
61180a9ef05SNatalie Beams     array: *const crate::Scalar,
6129df49d7eSJed Brown }
6139df49d7eSJed Brown 
6149df49d7eSJed Brown impl<'a> VectorView<'a> {
6159df49d7eSJed Brown     /// Construct a VectorView from a Vector reference
6169df49d7eSJed Brown     fn new(vec: &'a Vector) -> Self {
6179df49d7eSJed Brown         let mut array = std::ptr::null();
6189df49d7eSJed Brown         unsafe {
6199df49d7eSJed Brown             bind_ceed::CeedVectorGetArrayRead(
6209df49d7eSJed Brown                 vec.ptr,
6219df49d7eSJed Brown                 crate::MemType::Host as bind_ceed::CeedMemType,
6229df49d7eSJed Brown                 &mut array,
6239df49d7eSJed Brown             );
6249df49d7eSJed Brown         }
6259df49d7eSJed Brown         Self {
6269df49d7eSJed Brown             vec: vec,
6279df49d7eSJed Brown             array: array,
6289df49d7eSJed Brown         }
6299df49d7eSJed Brown     }
6309df49d7eSJed Brown }
6319df49d7eSJed Brown 
6329df49d7eSJed Brown // Destructor
6339df49d7eSJed Brown impl<'a> Drop for VectorView<'a> {
6349df49d7eSJed Brown     fn drop(&mut self) {
6359df49d7eSJed Brown         unsafe {
6369df49d7eSJed Brown             bind_ceed::CeedVectorRestoreArrayRead(self.vec.ptr, &mut self.array);
6379df49d7eSJed Brown         }
6389df49d7eSJed Brown     }
6399df49d7eSJed Brown }
6409df49d7eSJed Brown 
6419df49d7eSJed Brown // Data access
6429df49d7eSJed Brown impl<'a> Deref for VectorView<'a> {
64380a9ef05SNatalie Beams     type Target = [crate::Scalar];
64480a9ef05SNatalie Beams     fn deref(&self) -> &[crate::Scalar] {
6459df49d7eSJed Brown         unsafe { std::slice::from_raw_parts(self.array, self.vec.len()) }
6469df49d7eSJed Brown     }
6479df49d7eSJed Brown }
6489df49d7eSJed Brown 
6499df49d7eSJed Brown // Viewing
6509df49d7eSJed Brown impl<'a> fmt::Display for VectorView<'a> {
6519df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6529df49d7eSJed Brown         write!(f, "VectorView({:?})", self.deref())
6539df49d7eSJed Brown     }
6549df49d7eSJed Brown }
6559df49d7eSJed Brown 
6569df49d7eSJed Brown // -----------------------------------------------------------------------------
6579df49d7eSJed Brown // Vector Viewer Mutable
6589df49d7eSJed Brown // -----------------------------------------------------------------------------
6599df49d7eSJed Brown /// A mutable (host) view of a Vector with Deref to slice.
6609df49d7eSJed Brown #[derive(Debug)]
6619df49d7eSJed Brown pub struct VectorViewMut<'a> {
6629df49d7eSJed Brown     vec: &'a Vector<'a>,
66380a9ef05SNatalie Beams     array: *mut crate::Scalar,
6649df49d7eSJed Brown }
6659df49d7eSJed Brown 
6669df49d7eSJed Brown impl<'a> VectorViewMut<'a> {
6679df49d7eSJed Brown     /// Construct a VectorViewMut from a Vector reference
6689df49d7eSJed Brown     fn new(vec: &'a mut Vector) -> Self {
6699df49d7eSJed Brown         let mut ptr = std::ptr::null_mut();
6709df49d7eSJed Brown         unsafe {
6719df49d7eSJed Brown             bind_ceed::CeedVectorGetArray(
6729df49d7eSJed Brown                 vec.ptr,
6739df49d7eSJed Brown                 crate::MemType::Host as bind_ceed::CeedMemType,
6749df49d7eSJed Brown                 &mut ptr,
6759df49d7eSJed Brown             );
6769df49d7eSJed Brown         }
6779df49d7eSJed Brown         Self {
6789df49d7eSJed Brown             vec: vec,
6799df49d7eSJed Brown             array: ptr,
6809df49d7eSJed Brown         }
6819df49d7eSJed Brown     }
6829df49d7eSJed Brown }
6839df49d7eSJed Brown 
6849df49d7eSJed Brown // Destructor
6859df49d7eSJed Brown impl<'a> Drop for VectorViewMut<'a> {
6869df49d7eSJed Brown     fn drop(&mut self) {
6879df49d7eSJed Brown         unsafe {
6889df49d7eSJed Brown             bind_ceed::CeedVectorRestoreArray(self.vec.ptr, &mut self.array);
6899df49d7eSJed Brown         }
6909df49d7eSJed Brown     }
6919df49d7eSJed Brown }
6929df49d7eSJed Brown 
6939df49d7eSJed Brown // Data access
6949df49d7eSJed Brown impl<'a> Deref for VectorViewMut<'a> {
69580a9ef05SNatalie Beams     type Target = [crate::Scalar];
69680a9ef05SNatalie Beams     fn deref(&self) -> &[crate::Scalar] {
6979df49d7eSJed Brown         unsafe { std::slice::from_raw_parts(self.array, self.vec.len()) }
6989df49d7eSJed Brown     }
6999df49d7eSJed Brown }
7009df49d7eSJed Brown 
7019df49d7eSJed Brown // Mutable data access
7029df49d7eSJed Brown impl<'a> DerefMut for VectorViewMut<'a> {
70380a9ef05SNatalie Beams     fn deref_mut(&mut self) -> &mut [crate::Scalar] {
7049df49d7eSJed Brown         unsafe { std::slice::from_raw_parts_mut(self.array, self.vec.len()) }
7059df49d7eSJed Brown     }
7069df49d7eSJed Brown }
7079df49d7eSJed Brown 
7089df49d7eSJed Brown // Viewing
7099df49d7eSJed Brown impl<'a> fmt::Display for VectorViewMut<'a> {
7109df49d7eSJed Brown     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7119df49d7eSJed Brown         write!(f, "VectorViewMut({:?})", self.deref())
7129df49d7eSJed Brown     }
7139df49d7eSJed Brown }
7149df49d7eSJed Brown 
7159df49d7eSJed Brown // -----------------------------------------------------------------------------
716