@@ -11,6 +11,7 @@ use std::fmt;
1111use std:: mem;
1212use std:: os;
1313use std:: ptr;
14+ use std:: result:: Result as StdResult ;
1415use std:: slice;
1516
1617pub mod option;
@@ -47,8 +48,14 @@ pub enum Error {
4748
4849impl std:: error:: Error for Error { }
4950
50- impl From < NewError > for Error {
51- fn from ( _: NewError ) -> Self {
51+ impl From < NewGraphError > for Error {
52+ fn from ( _: NewGraphError ) -> Self {
53+ Self :: Input
54+ }
55+ }
56+
57+ impl From < NewMeshError > for Error {
58+ fn from ( _: NewMeshError ) -> Self {
5259 Self :: Input
5360 }
5461}
@@ -64,7 +71,7 @@ impl fmt::Display for Error {
6471}
6572
6673/// The result of a partitioning.
67- pub type Result < T > = std :: result :: Result < T , Error > ;
74+ pub type Result < T > = StdResult < T , Error > ;
6875
6976trait ErrorCode {
7077 /// Makes a [`Result`] from a return code (int) from METIS.
@@ -83,53 +90,62 @@ impl ErrorCode for m::rstatus_et {
8390 }
8491}
8592
93+ /// Error raised when the graph data fed to [`Graph::new`] cannot be safely
94+ /// passed to METIS.
95+ ///
96+ /// Graph data must follow the format described in [`Graph::new`].
8697#[ derive( Debug ) ]
87- enum NewErrorKind {
88- InvalidNumberOfConstraints ,
89- InvalidNumberOfParts ,
90- XadjIsEmpty ,
91- XadjIsTooLarge ,
92- XadjIsNotSorted ,
93- InvalidLastXadj ,
94- BadAdjncyLength ,
95- AdjncyOutOfBounds ,
98+ pub struct InvalidGraphError {
99+ msg : & ' static str ,
96100}
97101
98- impl fmt:: Display for NewErrorKind {
102+ impl fmt:: Display for InvalidGraphError {
99103 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
100- match self {
101- Self :: InvalidNumberOfConstraints => write ! ( f, "ncon must be strictly positive" ) ,
102- Self :: InvalidNumberOfParts => write ! ( f, "nparts must be strictly positive" ) ,
103- Self :: XadjIsEmpty => write ! ( f, "xadj/eptr is empty" ) ,
104- Self :: XadjIsTooLarge => write ! ( f, "xadj/eptr's length cannot be held by an Idx" ) ,
105- Self :: XadjIsNotSorted => write ! ( f, "xadj/eptr is not sorted" ) ,
106- Self :: InvalidLastXadj => write ! ( f, "the last element of xadj/eptr is invalid" ) ,
107- Self :: BadAdjncyLength => write ! (
108- f,
109- "the last element of xadj/eptr must be adjncy/eind's length"
110- ) ,
111-
112- Self :: AdjncyOutOfBounds => write ! ( f, "an element of adjncy/eind is out of bounds" ) ,
113- }
104+ self . msg . fmt ( f)
114105 }
115106}
116107
117- /// Error type returned by [`Graph::new`] and [`Mesh::new`] .
108+ /// Error type returned by [`Graph::new`].
118109///
119- /// This error means the input arrays are malformed and cannot be safely passed
120- /// to METIS.
110+ /// Unlike [`Error`], this error originates from the Rust bindings.
121111#[ derive( Debug ) ]
122- pub struct NewError {
123- kind : NewErrorKind ,
112+ #[ non_exhaustive]
113+ pub enum NewGraphError {
114+ /// `ncon` must be greater than 1.
115+ NoConstraints ,
116+
117+ /// `nparts` must be greater than 1.
118+ NoParts ,
119+
120+ /// Graph is too large. One of the array's length doesn't fit into [`Idx`].
121+ TooLarge ,
122+
123+ /// The input arrays are malformed and cannot be safely passed to METIS.
124+ ///
125+ /// Note that these bindings do not check for all the invariants. Some might
126+ /// be raised during [`Graph::part_recursive`] and [`Graph::part_kway`] as
127+ /// [`Error::Input`].
128+ InvalidGraph ( InvalidGraphError ) ,
124129}
125130
126- impl fmt:: Display for NewError {
131+ impl fmt:: Display for NewGraphError {
127132 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
128- self . kind . fmt ( f)
133+ match self {
134+ Self :: NoConstraints => write ! ( f, "there must be at least one constraint" ) ,
135+ Self :: NoParts => write ! ( f, "there must be at least one part" ) ,
136+ Self :: TooLarge => write ! ( f, "graph is too large" ) ,
137+ Self :: InvalidGraph ( err) => write ! ( f, "invalid graph structure: {err}" ) ,
138+ }
129139 }
130140}
131141
132- impl std:: error:: Error for NewError { }
142+ impl std:: error:: Error for NewGraphError { }
143+
144+ impl NewGraphError {
145+ fn msg ( msg : & ' static str ) -> Self {
146+ Self :: InvalidGraph ( InvalidGraphError { msg } )
147+ }
148+ }
133149
134150/// Builder structure to setup a graph partition computation.
135151///
@@ -283,53 +299,44 @@ impl<'a> Graph<'a> {
283299 nparts : Idx ,
284300 xadj : & ' a mut [ Idx ] ,
285301 adjncy : & ' a mut [ Idx ] ,
286- ) -> std :: result :: Result < Graph < ' a > , NewError > {
302+ ) -> StdResult < Graph < ' a > , NewGraphError > {
287303 if ncon <= 0 {
288- return Err ( NewError {
289- kind : NewErrorKind :: InvalidNumberOfConstraints ,
290- } ) ;
304+ return Err ( NewGraphError :: NoConstraints ) ;
291305 }
292306 if nparts <= 0 {
293- return Err ( NewError {
294- kind : NewErrorKind :: InvalidNumberOfParts ,
295- } ) ;
307+ return Err ( NewGraphError :: NoParts ) ;
296308 }
297309
298- let last_xadj = xadj. last ( ) . ok_or ( NewError {
299- kind : NewErrorKind :: XadjIsEmpty ,
300- } ) ?;
301- let last_xadj = usize:: try_from ( * last_xadj) . map_err ( |_| NewError {
302- kind : NewErrorKind :: InvalidLastXadj ,
303- } ) ?;
304- if last_xadj != adjncy. len ( ) {
305- return Err ( NewError {
306- kind : NewErrorKind :: BadAdjncyLength ,
307- } ) ;
310+ let last_xadj = * xadj
311+ . last ( )
312+ . ok_or ( NewGraphError :: msg ( "index list is empty" ) ) ?;
313+ let adjncy_len = Idx :: try_from ( adjncy. len ( ) ) . map_err ( |_| NewGraphError :: TooLarge ) ?;
314+ if last_xadj != adjncy_len {
315+ return Err ( NewGraphError :: msg (
316+ "length mismatch between index and adjacency lists" ,
317+ ) ) ;
308318 }
309319
320+ let nvtxs = match Idx :: try_from ( xadj. len ( ) ) {
321+ Ok ( xadj_len) => xadj_len - 1 ,
322+ Err ( _) => {
323+ return Err ( NewGraphError :: TooLarge ) ;
324+ }
325+ } ;
326+
310327 let mut prev = 0 ;
311328 for x in & * xadj {
312329 if prev > * x {
313- return Err ( NewError {
314- kind : NewErrorKind :: XadjIsNotSorted ,
315- } ) ;
330+ return Err ( NewGraphError :: msg ( "index list is not sorted" ) ) ;
316331 }
317332 prev = * x;
318333 }
319334
320- let nvtxs = match Idx :: try_from ( xadj. len ( ) ) {
321- Ok ( xadj_len) => xadj_len - 1 ,
322- Err ( _) => {
323- return Err ( NewError {
324- kind : NewErrorKind :: XadjIsTooLarge ,
325- } )
326- }
327- } ;
328335 for a in & * adjncy {
329336 if * a < 0 || * a >= nvtxs {
330- return Err ( NewError {
331- kind : NewErrorKind :: AdjncyOutOfBounds ,
332- } ) ;
337+ return Err ( NewGraphError :: msg (
338+ "some values in the adjacency list are out of bounds" ,
339+ ) ) ;
333340 }
334341 }
335342
@@ -651,42 +658,94 @@ impl<'a> Graph<'a> {
651658 }
652659}
653660
654- /// Check the given mesh structure for any construct that might make METIS
655- /// segfault or otherwise corrupt memory .
661+ /// Error raised when the mesh data fed to [`Mesh::new`] cannot be safely passed
662+ /// to METIS .
656663///
657- /// Returns the number of nodes in the mesh.
658- fn check_mesh_structure ( eptr : & [ Idx ] , eind : & [ Idx ] ) -> std:: result:: Result < Idx , NewError > {
664+ /// Mesh data must follow the format described in [`Mesh::new`].
665+ #[ derive( Debug ) ]
666+ pub struct InvalidMeshError {
667+ msg : & ' static str ,
668+ }
669+
670+ impl fmt:: Display for InvalidMeshError {
671+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
672+ self . msg . fmt ( f)
673+ }
674+ }
675+
676+ /// Error type returned by [`Mesh::new`].
677+ ///
678+ /// Unlike [`Error`], this error originates from the Rust bindings.
679+ #[ derive( Debug ) ]
680+ #[ non_exhaustive]
681+ pub enum NewMeshError {
682+ /// `nparts` must be greater than 1.
683+ NoParts ,
684+
685+ /// Mesh is too large. One of the array's length doesn't fit into [`Idx`].
686+ TooLarge ,
687+
688+ /// The input arrays are malformed and cannot be safely passed to METIS.
689+ ///
690+ /// Note that these bindings do not check for all the invariants. Some might
691+ /// be raised during [`Mesh::part_dual`] and [`Mesh::part_nodal`] as
692+ /// [`Error::Input`].
693+ InvalidMesh ( InvalidMeshError ) ,
694+ }
695+
696+ impl fmt:: Display for NewMeshError {
697+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
698+ match self {
699+ Self :: NoParts => write ! ( f, "there must be at least one part" ) ,
700+ Self :: TooLarge => write ! ( f, "mesh is too large" ) ,
701+ Self :: InvalidMesh ( err) => write ! ( f, "invalid mesh structure: {err}" ) ,
702+ }
703+ }
704+ }
705+
706+ impl std:: error:: Error for NewMeshError { }
707+
708+ impl NewMeshError {
709+ fn msg ( msg : & ' static str ) -> Self {
710+ Self :: InvalidMesh ( InvalidMeshError { msg } )
711+ }
712+ }
713+
714+ /// Returns the number of elements and the number of nodes in the mesh.
715+ fn check_mesh_structure ( eptr : & [ Idx ] , eind : & [ Idx ] ) -> StdResult < ( Idx , Idx ) , NewMeshError > {
716+ let last_eptr = * eptr
717+ . last ( )
718+ . ok_or ( NewMeshError :: msg ( "element index is empty" ) ) ?;
719+ let eind_len = Idx :: try_from ( eind. len ( ) ) . map_err ( |_| NewMeshError :: TooLarge ) ?;
720+ if last_eptr != eind_len {
721+ return Err ( NewMeshError :: msg (
722+ "length mismatch between element and node indices" ,
723+ ) ) ;
724+ }
725+
726+ let ne = Idx :: try_from ( eptr. len ( ) ) . map_err ( |_| NewMeshError :: TooLarge ) ? - 1 ;
727+
659728 let mut prev = 0 ;
660729 for x in eptr {
661730 if prev > * x {
662- return Err ( NewError {
663- kind : NewErrorKind :: XadjIsNotSorted ,
664- } ) ;
731+ return Err ( NewMeshError :: msg ( "element index is not sorted" ) ) ;
665732 }
666733 prev = * x;
667734 }
668- let last_eptr = usize:: try_from ( prev) . map_err ( |_| NewError {
669- kind : NewErrorKind :: InvalidLastXadj ,
670- } ) ?;
671- if last_eptr != eind. len ( ) {
672- return Err ( NewError {
673- kind : NewErrorKind :: BadAdjncyLength ,
674- } ) ;
675- }
676735
677736 let mut max_node = 0 ;
678737 for a in eind {
679738 if * a < 0 {
680- return Err ( NewError {
681- kind : NewErrorKind :: AdjncyOutOfBounds ,
682- } ) ;
739+ return Err ( NewMeshError :: msg (
740+ "values in the node index are out of bounds" ,
741+ ) ) ;
683742 }
684743 if * a > max_node {
685744 max_node = * a;
686745 }
687746 }
688747
689- Ok ( max_node + 1 )
748+ Ok ( ( ne , max_node + 1 ) )
690749}
691750
692751/// Builder structure to setup a mesh partition computation.
@@ -769,13 +828,11 @@ impl<'a> Mesh<'a> {
769828 nparts : Idx ,
770829 eptr : & ' a mut [ Idx ] ,
771830 eind : & ' a mut [ Idx ] ,
772- ) -> std :: result :: Result < Mesh < ' a > , NewError > {
831+ ) -> StdResult < Mesh < ' a > , NewMeshError > {
773832 if nparts <= 0 {
774- return Err ( NewError {
775- kind : NewErrorKind :: InvalidNumberOfParts ,
776- } ) ;
833+ return Err ( NewMeshError :: NoParts ) ;
777834 }
778- let nn = check_mesh_structure ( & * eptr, & * eind) ?;
835+ let ( _ne , nn ) = check_mesh_structure ( & * eptr, & * eind) ?;
779836 Ok ( unsafe { Mesh :: new_unchecked ( nn, nparts, eptr, eind) } )
780837 }
781838
@@ -1066,15 +1123,12 @@ impl Drop for Dual {
10661123
10671124/// Generate the dual graph of a mesh.
10681125///
1069- /// # Panics
1070- ///
1071- /// This function panics if:
1126+ /// # Errors
10721127///
1073- /// - `eptr` is empty, or
1074- /// - `eptr`'s length doesn't fit in [`Idx `].
1128+ /// This function returns an error if `eptr` and `eind` don't follow the mesh
1129+ /// format given in [`Mesh::new `].
10751130pub fn mesh_to_dual ( eptr : & mut [ Idx ] , eind : & mut [ Idx ] , mut ncommon : Idx ) -> Result < Dual > {
1076- let nn = & mut check_mesh_structure ( & * eptr, & * eind) ?;
1077- let ne = & mut ( eptr. len ( ) as Idx - 1 ) ; // `as` cast already checked by `check_mesh_structure`
1131+ let ( mut ne, mut nn) = check_mesh_structure ( & * eptr, & * eind) ?;
10781132 let mut xadj = mem:: MaybeUninit :: uninit ( ) ;
10791133 let mut adjncy = mem:: MaybeUninit :: uninit ( ) ;
10801134 let mut numbering_flag = 0 ;
@@ -1083,8 +1137,8 @@ pub fn mesh_to_dual(eptr: &mut [Idx], eind: &mut [Idx], mut ncommon: Idx) -> Res
10831137 // SAFETY: hopefully those arrays are of correct length.
10841138 unsafe {
10851139 m:: METIS_MeshToDual (
1086- ne,
1087- nn,
1140+ & mut ne,
1141+ & mut nn,
10881142 eptr. as_mut_ptr ( ) ,
10891143 eind. as_mut_ptr ( ) ,
10901144 & mut ncommon,
0 commit comments