try_create/
lib.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! This crate provides a set of traits for standardizing object creation
4//! patterns in Rust, covering infallible, fallible, conditional, and
5//! policy-based validated construction.
6//!
7//! # Core Traits
8//!
9//! - [`IntoInner`]: A trait for types that can be converted into an "inner"
10//!   value. This is often a prerequisite for construction traits.
11//! - [`TryNew`]: For fallible construction that returns a [`Result`]. Use this
12//!   when creating an instance might fail due to validation or other reasons.
13//! - [`New`]: For infallible construction. If creation cannot logically fail
14//!   (or if failure should deterministically panic), use this trait.
15//!
16//! # Advanced Construction Patterns
17//!
18//! - [`ConditionallyCreate`]: Provides a `create_conditionally` method that
19//!   behaves differently in debug and release builds. In debug, it uses
20//!   `TryNew::try_new().expect()`, panicking on failure. In release, it uses
21//!   `New::new()`. This is useful for enforcing stricter checks during
22//!   development.
23//! - [`ValidationPolicy`]: Defines a contract for validation logic. A policy
24//!   specifies how a value should be validated and what error type is
25//!   returned upon failure. This allows for reusable validation strategies.
26//! - [`TryNewValidated`]: Extends [`TryNew`] by associating a specific
27//!   [`ValidationPolicy`] with the type. The [`TryNewValidated::try_new_validated`] method
28//!   first applies the policy and then, if successful, proceeds with the
29//!   underlying [`TryNew`] construction logic. This enables a two-phase
30//!   construction process: external validation followed by internal creation.
31//!
32//! # Features
33//!
34//! - `std`: (Enabled by default) When enabled, the `Error` associated type
35//!   for [`TryNew`] and [`ValidationPolicy`] is bound by `std::error::Error`.
36//! - If `std` is not enabled, their `Error` types are bound by `core::fmt::Debug`.
37//!
38//! # Examples
39//!
40//! See the documentation for individual traits for specific examples.
41
42// Re-export IntoInner for convenience, as it's a supertrait of TryNew.
43pub use into_inner::IntoInner;
44
45use duplicate::duplicate_item;
46use num::Complex;
47use std::convert::Infallible;
48
49/// A trait for creating new instances of a type with fallible validation.
50///
51/// This trait provides a standardized way to create new instances of a type from an
52/// "inner" value, where the construction process might fail (e.g., due to validation rules).
53/// Implementors must also implement [`IntoInner`], which defines the `InnerType` used
54/// for construction.
55///
56/// # Associated Types
57///
58/// - `InnerType`: (From the [`IntoInner`] supertrait) The type of the input value used to
59///   attempt creation of a new instance of `Self`.
60/// - `Error`: The error type that is returned if `try_new` fails. This error type
61///   must implement `std::error::Error` if the `std` feature is enabled.
62///   If the `std` feature is not enabled, it must implement `core::fmt::Debug`.
63///
64/// # Examples
65///
66/// ```rust
67/// use try_create::{TryNew, IntoInner};
68/// # #[cfg(feature = "std")]
69/// # use std::error::Error;
70/// # #[cfg(feature = "std")]
71/// # use core::fmt;
72///
73/// // Define a custom error type
74/// #[derive(Debug, PartialEq)]
75/// struct NotPositiveError;
76///
77/// // Implement Display and Error for the custom error (required if using std::error::Error)
78/// # #[cfg(feature = "std")]
79/// impl fmt::Display for NotPositiveError {
80///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81///         write!(f, "Value must be positive")
82///     }
83/// }
84/// # #[cfg(feature = "std")]
85/// impl Error for NotPositiveError {}
86/// # #[cfg(not(feature = "std"))]
87/// # trait Error: core::fmt::Debug {} // Minimal Error trait for no_std
88/// # #[cfg(not(feature = "std"))]
89/// # impl Error for NotPositiveError {}
90///
91///
92/// // A struct that wraps an i32, ensuring it's positive.
93/// #[derive(Debug, PartialEq)]
94/// struct PositiveInteger {
95///     value: i32,
96/// }
97///
98/// // Implement IntoInner to define what `InnerType` is.
99/// impl IntoInner for PositiveInteger {
100///     type InnerType = i32;
101///
102///     fn into_inner(self) -> Self::InnerType {
103///         self.value
104///     }
105/// }
106///
107/// // Implement TryNew for PositiveInteger.
108/// impl TryNew for PositiveInteger {
109///     type Error = NotPositiveError;
110///     // `InnerType` is `i32`, inherited from `IntoInner`.
111///
112///     fn try_new(value: Self::InnerType) -> Result<Self, Self::Error> {
113///         if value > 0 {
114///             Ok(PositiveInteger { value })
115///         } else {
116///             Err(NotPositiveError)
117///         }
118///     }
119/// }
120///
121/// // Usage
122/// assert_eq!(PositiveInteger::try_new(10), Ok(PositiveInteger { value: 10 }));
123/// assert_eq!(PositiveInteger::try_new(0), Err(NotPositiveError));
124/// assert_eq!(PositiveInteger::try_new(-5), Err(NotPositiveError));
125///
126/// let positive_num = PositiveInteger::try_new(42).unwrap();
127/// assert_eq!(positive_num.into_inner(), 42);
128/// ```
129pub trait TryNew: Sized + IntoInner {
130    /// The error type that can be returned by the `try_new` method.
131    #[cfg(feature = "std")]
132    type Error: std::error::Error;
133    #[cfg(not(feature = "std"))]
134    type Error: core::fmt::Debug; // Added for no_std consistency
135
136    /// Attempts to create a new instance of `Self` from `value`.
137    ///
138    /// # Parameters
139    ///
140    /// - `value`: The `InnerType` value from which to create the instance.
141    ///
142    /// # Returns
143    ///
144    /// - `Ok(Self)` if the instance is created successfully.
145    /// - `Err(Self::Error)` if creation fails (e.g., due to invalid input).
146    fn try_new(value: Self::InnerType) -> Result<Self, Self::Error>;
147}
148
149/// A trait for creating new instances of a type infallibly.
150///
151/// This trait provides a method for creating new instances of a type from `Self::InnerType`
152/// (defined by the `IntoInner` supertrait).
153///
154/// Implementors should ensure that the [`New`] method cannot fail in a way that would
155/// typically return a `Result`. If invalid input could lead to an unrecoverable state
156/// or violate invariants, [`New`] should panic. For fallible construction that returns
157/// a `Result`, use the [[`TryNew`]] trait.
158///
159/// # Examples
160///
161/// ```rust
162/// use try_create::{New, IntoInner, TryNew}; // Assuming TryNew is used for context or comparison
163/// # #[cfg(feature = "std")]
164/// # use std::error::Error;
165/// # #[cfg(feature = "std")]
166/// # use std::fmt;
167///
168/// // Example struct
169/// #[derive(Debug, PartialEq)]
170/// struct MyType(i32);
171///
172/// // Define a custom error for MyType for the TryNew example
173/// #[derive(Debug, PartialEq)]
174/// struct MyTypeError(String);
175///
176/// // Implement Display and Error for MyTypeError
177/// # #[cfg(feature = "std")]
178/// impl fmt::Display for MyTypeError {
179///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180///         write!(f, "MyTypeError: {}", self.0)
181///     }
182/// }
183///
184/// # #[cfg(feature = "std")]
185/// impl Error for MyTypeError {}
186/// // For no_std, MyTypeError already derives Debug, which is sufficient.
187///
188/// impl IntoInner for MyType {
189///     type InnerType = i32;
190///     fn into_inner(self) -> Self::InnerType { self.0 }
191/// }
192///
193/// // Example TryNew (optional here, but good for context)
194/// impl TryNew for MyType {
195///     type Error = MyTypeError; // Use the custom error type
196///     fn try_new(value: i32) -> Result<Self, Self::Error> {
197///         if value < 0 { Err(MyTypeError("Value cannot be negative".to_string())) }
198///         else { Ok(MyType(value)) }
199///     }
200/// }
201///
202/// impl New for MyType {
203///     fn new(value: i32) -> Self {
204///         if value < 0 {
205///             panic!("MyType::new: Value cannot be negative");
206///         }
207///         MyType(value)
208///     }
209/// }
210///
211/// assert_eq!(MyType::new(10), MyType(10));
212/// // The following would panic:
213/// // MyType::new(-5);
214/// ```
215pub trait New: Sized + IntoInner {
216    /// Creates a new instance of `Self` from `value`.
217    ///
218    /// This method is expected to be infallible in terms of returning a `Result`.
219    /// If the provided `value` cannot produce a valid instance of `Self`
220    /// according to the type's invariants, this method should panic.
221    ///
222    /// # Parameters
223    ///
224    /// - `value`: The `Self::InnerType` value from which to create the instance.
225    fn new(value: Self::InnerType) -> Self;
226}
227
228// It's necessary to import Debug for the bound on TryNew's error type.
229// This is implicitly handled if `std::error::Error` is used (as it requires Debug)
230// or if `core::fmt::Debug` is directly used for no_std.
231// For clarity, if you were in a module that didn't automatically have `std::fmt::Debug`
232// or `core::fmt::Debug` in scope, you might need:
233// use core::fmt::Debug; // or std::fmt::Debug if std is assumed
234
235/// A trait for conditionally creating objects.
236///
237/// In debug mode, it uses `Self::try_new().expect()` to create an instance,
238/// panicking if `try_new` returns an error.
239/// In release mode, it uses `Self::new()` to create an instance.
240///
241/// This trait requires the type to also implement [`TryNew`] and [`New`].
242/// The error associated with [`TryNew`] (`<Self as TryNew>::Error`) must implement [`Debug`].
243///
244/// # Example
245/// ```rust
246/// use try_create::{ConditionallyCreate, TryNew, New, IntoInner};
247/// # // Copied from TryNew example for self-containment, adjust if shared
248/// # #[cfg(feature = "std")]
249/// # use std::error::Error;
250/// # #[cfg(feature = "std")]
251/// # use std::fmt;
252///
253/// #[derive(Debug, PartialEq)]
254/// struct NotPositiveError;
255///
256/// # #[cfg(feature = "std")]
257/// impl fmt::Display for NotPositiveError {
258///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259///         write!(f, "Value must be positive")
260///     }
261/// }
262/// # #[cfg(feature = "std")]
263/// impl Error for NotPositiveError {}
264/// # #[cfg(not(feature = "std"))]
265/// # trait Error: core::fmt::Debug {} // Minimal Error trait for no_std
266/// # #[cfg(not(feature = "std"))]
267/// # impl Error for NotPositiveError {}
268///
269///
270/// #[derive(Debug, PartialEq)]
271/// struct PositiveInteger { value: i32 }
272///
273/// impl IntoInner for PositiveInteger {
274///     type InnerType = i32;
275///     fn into_inner(self) -> Self::InnerType { self.value }
276/// }
277///
278/// impl TryNew for PositiveInteger {
279///     type Error = NotPositiveError;
280///     fn try_new(value: Self::InnerType) -> Result<Self, Self::Error> {
281///         if value > 0 { Ok(PositiveInteger { value }) }
282///         else { Err(NotPositiveError) }
283///     }
284/// }
285///
286/// // To use ConditionallyCreate, PositiveInteger must also implement New.
287/// impl New for PositiveInteger {
288///     fn new(value: Self::InnerType) -> Self {
289///         match Self::try_new(value) {
290///             Ok(instance) => instance,
291///             Err(e) => panic!("PositiveInteger::new failed for a non-positive value. Error: {:?}", e),
292///         }
293///     }
294/// }
295///
296/// // Now you can call:
297/// # fn example_usage() { // Encapsulate in a function for the doctest
298/// let val_ok = 10;
299/// let _p1 = PositiveInteger::create_conditionally(val_ok);
300/// assert_eq!(_p1, PositiveInteger { value: 10 });
301///
302/// // In debug, this would panic (difficult to test directly in doctest without specific harness):
303/// // let val_err = -5;
304/// // let _p2 = PositiveInteger::create_conditionally(val_err);
305/// # }
306/// # example_usage();
307/// ```
308pub trait ConditionallyCreate: Sized + TryNew + New
309where
310    <Self as TryNew>::Error: core::fmt::Debug,
311{
312    /// Conditionally creates an instance of `Self`.
313    ///
314    /// # Parameters
315    ///
316    /// - `value`: The `Self::InnerType` value (defined by `IntoInner`)
317    ///   from which to create the instance.
318    ///
319    /// # Panics
320    ///
321    /// In debug mode, this method will panic if `Self::try_new(value)`
322    /// returns `Err`. The panic message will include the error's description.
323    /// In release mode, the panic behavior depends on the implementation
324    /// of `Self::new(value)`.
325    fn create_conditionally(value: Self::InnerType) -> Self {
326        #[cfg(debug_assertions)]
327        {
328            // In debug mode, use try_new and panic on error.
329            Self::try_new(value).expect("ConditionallyCreate: try_new() failed in debug mode")
330        }
331        #[cfg(not(debug_assertions))]
332        {
333            // In release mode, use new (which is assumed to be infallible
334            // or to handle failure internally, e.g., by panicking).
335            Self::new(value)
336        }
337    }
338}
339
340// Blanket implementation of `ConditionallyCreate` for all types `T`
341// that implement [`TryNew`] and [`New`], and whose `TryNew::Error` type
342// implements `Debug`.
343impl<T> ConditionallyCreate for T
344where
345    T: TryNew + New,
346    <T as TryNew>::Error: core::fmt::Debug, // This bound is inherited from the trait definition
347{
348    // The `create_conditionally` method already has a default implementation in the trait,
349    // so it doesn't need to be redefined here.
350}
351
352/// Defines a contract for validation policies.
353///
354/// A validation policy specifies how a value of a certain type (`Value`)
355/// should be validated and what error type (`Error`) is returned upon failure.
356///
357/// # Associated Types
358///
359/// - `Value`: The type of the value to be validated.
360/// - `Error`: The type of the error returned if validation fails. This error type
361///   must implement [`std::error::Error`] if the `std` feature is enabled.
362///   If the `std` feature is not enabled, it must implement [`core::fmt::Debug`].
363pub trait ValidationPolicy {
364    /// The type of the value to be validated.
365    type Value;
366
367    /// The type of the error returned if validation fails.
368    #[cfg(feature = "std")]
369    type Error: std::error::Error;
370    #[cfg(not(feature = "std"))]
371    type Error: core::fmt::Debug; // For no_std consistency
372
373    /// Validates a value by consuming it.
374    ///
375    /// If validation is successful, the original value is returned.
376    /// Otherwise, an error is returned.
377    /// This default implementation calls [`Self::validate_ref()]`.
378    fn validate(v: Self::Value) -> Result<Self::Value, Self::Error> {
379        Self::validate_ref(&v)?;
380        Ok(v)
381    }
382
383    /// Validates a value by reference.
384    ///
385    /// Returns `Ok(())` if validation is successful, otherwise an error is returned.
386    /// This method must be implemented by concrete policies.
387    fn validate_ref(v: &Self::Value) -> Result<(), Self::Error>;
388}
389
390/// A trait for creating new instances of a type with fallible validation,
391/// where the validation logic is defined by an associated `ValidationPolicy`.
392///
393/// This trait extends [`TryNew`] by associating a specific [`ValidationPolicy`]
394/// with the type. The [`Self::try_new_validated()`] method first uses this policy to validate
395/// the input value. If validation succeeds, it then typically calls the underlying
396/// `try_new` method (or a similar construction logic) to create the instance.
397///
398/// # Supertraits
399///
400/// - [`TryNew`]: Implementors of `TryNewValidated` must also implement `TryNew`.
401///   This means they must define an `InnerType` (via the [`IntoInner`] supertrait of `TryNew`),
402///   an `Error` type, and a `try_new` method.
403pub trait TryNewValidated: TryNew {
404    /// An implementor of [`ValidationPolicy`].
405    /// - The `Value` associated type of this `Policy` must be the same as the
406    ///   `InnerType` of `Self` (i.e., `Self::Policy::Value == <Self as IntoInner>::InnerType`).
407    /// - The `Error` associated type of this `Policy` must be convertible into
408    ///   `Self::Error` (the error type defined by the `TryNew` trait for `Self`).
409    ///   This is ensured by the `From` bound on `Self::Error`.
410    type Policy: ValidationPolicy<Value = <Self as IntoInner>::InnerType>;
411
412    /// Attempts to create a new instance of `Self` from `value`.
413    /// This method should first validate `value` using `Self::Policy::validate_ref(&value)`
414    /// (or `Self::Policy::validate(value)` if consuming the value is intended by the policy).
415    /// If validation is successful, it proceeds to construct the `Self` instance,
416    /// typically by calling `Self::try_new(value)`.
417    /// If validation fails, the error from the policy is converted into `Self::Error` and returned.
418    /// If construction after successful validation fails, the error from `Self::try_new` is returned.
419    fn try_new_validated(
420        value: <Self as IntoInner>::InnerType,
421    ) -> Result<Self, Self::Error>
422    where
423        Self: Sized;
424}
425
426#[duplicate_item(
427    T;
428    [f32];
429    [f64];
430    [i8];
431    [i16];
432    [i32];
433    [i64];
434    [i128];
435    [u8];
436    [u16];
437    [u32];
438    [u64];
439    [u128];
440    [isize];
441    [usize];
442    [bool];
443    [char];
444    [Complex<f32>];
445    [Complex<f64>];
446)]
447impl New for T {
448    /// Creates a new instance of the fundamental type from the given value.
449    ///
450    /// This implementation is infallible and simply returns the input value.
451    fn new(value: Self::InnerType) -> Self {
452        value
453    }
454}
455
456#[duplicate_item(
457    T;
458    [f32];
459    [f64];
460    [i8];
461    [i16];
462    [i32];
463    [i64];
464    [i128];
465    [u8];
466    [u16];
467    [u32];
468    [u64];
469    [u128];
470    [isize];
471    [usize];
472    [bool];
473    [char];
474    [Complex<f32>];
475    [Complex<f64>];
476)]
477impl TryNew for T {
478    type Error = Infallible; // No error type needed for fundamental types
479
480    /// Creates a new instance of the fundamental type from the given value.
481    ///
482    /// This implementation is infallible and simply returns the input value.
483    fn try_new(value: Self::InnerType) -> Result<Self, Infallible> {
484        Ok(value)
485    }
486}
487
488#[cfg(test)]
489mod tests {
490    use super::*; // Import traits from the parent module (your library)
491
492    // --- Test setup for PositiveInteger ---
493    #[derive(Debug, PartialEq)]
494    struct TestNotPositiveError;
495
496    // Implement Display and Error for TestNotPositiveError for std builds
497    #[cfg(feature = "std")]
498    impl std::fmt::Display for TestNotPositiveError {
499        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
500            write!(f, "Value must be positive (Test Error)")
501        }
502    }
503
504    #[cfg(feature = "std")]
505    impl std::error::Error for TestNotPositiveError {}
506
507    // For no_std, deriving Debug is sufficient as per TryNew's Error bound.
508
509    #[derive(Debug, PartialEq)]
510    struct TestPositiveInteger {
511        value: i32,
512    }
513
514    impl IntoInner for TestPositiveInteger {
515        type InnerType = i32;
516        fn into_inner(self) -> Self::InnerType {
517            self.value
518        }
519    }
520
521    impl TryNew for TestPositiveInteger {
522        type Error = TestNotPositiveError;
523        fn try_new(value: Self::InnerType) -> Result<Self, Self::Error> {
524            if value > 0 {
525                Ok(TestPositiveInteger { value })
526            } else {
527                Err(TestNotPositiveError)
528            }
529        }
530    }
531
532    impl New for TestPositiveInteger {
533        fn new(value: Self::InnerType) -> Self {
534            // Consistent with the example: panic if try_new would fail
535            match Self::try_new(value) {
536                Ok(instance) => instance,
537                Err(_) => panic!("TestPositiveInteger::new: Value must be positive."),
538            }
539        }
540    }
541
542    mod try_new {
543        use super::*; // Import traits from the parent module (your library)
544
545        // --- Tests for PositiveInteger ---
546        #[test]
547        fn test_positive_integer_try_new_ok() {
548            assert_eq!(
549                TestPositiveInteger::try_new(10),
550                Ok(TestPositiveInteger { value: 10 })
551            );
552        }
553
554        #[test]
555        fn test_positive_integer_try_new_err_zero() {
556            assert_eq!(TestPositiveInteger::try_new(0), Err(TestNotPositiveError));
557        }
558
559        #[test]
560        fn test_positive_integer_try_new_err_negative() {
561            assert_eq!(TestPositiveInteger::try_new(-5), Err(TestNotPositiveError));
562        }
563
564        // --- Tests for MyType ---
565        #[test]
566        fn test_my_type_try_new_ok() {
567            assert_eq!(TestMyType::try_new(5), Ok(TestMyType(5)));
568        }
569
570        #[test]
571        fn test_my_type_try_new_err() {
572            assert_eq!(
573                TestMyType::try_new(-1),
574                Err(TestMyTypeError("Value cannot be negative".to_string()))
575            );
576        }
577    } // mod try_new
578
579    mod new {
580        use super::*; // Import traits from the parent module (your library)
581
582        #[test]
583        fn test_positive_integer_new_ok() {
584            assert_eq!(
585                TestPositiveInteger::new(10),
586                TestPositiveInteger { value: 10 }
587            );
588        }
589
590        #[test]
591        #[should_panic(expected = "TestPositiveInteger::new: Value must be positive.")]
592        fn test_positive_integer_new_panic_zero() {
593            TestPositiveInteger::new(0);
594        }
595
596        #[test]
597        #[should_panic(expected = "TestPositiveInteger::new: Value must be positive.")]
598        fn test_positive_integer_new_panic_negative() {
599            TestPositiveInteger::new(-10);
600        }
601
602        #[test]
603        fn test_my_type_new_ok() {
604            assert_eq!(TestMyType::new(100), TestMyType(100));
605        }
606
607        #[test]
608        #[should_panic(expected = "TestMyType::new: Value cannot be negative")]
609        fn test_my_type_new_panic() {
610            TestMyType::new(-1);
611        }
612    } // mod new
613
614    mod into_inner {
615        use super::*;
616
617        #[test]
618        fn test_positive_integer_into_inner() {
619            let pi = TestPositiveInteger::new(42);
620            assert_eq!(pi.into_inner(), 42);
621        }
622
623        #[test]
624        fn test_my_type_into_inner() {
625            let mt = TestMyType::new(7);
626            assert_eq!(mt.into_inner(), 7);
627        }
628    }
629
630    // --- Test setup for MyType (from New example) ---
631    #[derive(Debug, PartialEq)]
632    struct TestMyTypeError(String);
633
634    #[cfg(feature = "std")]
635    impl std::fmt::Display for TestMyTypeError {
636        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
637            write!(f, "TestMyTypeError: {}", self.0)
638        }
639    }
640
641    #[cfg(feature = "std")]
642    impl std::error::Error for TestMyTypeError {}
643
644    #[derive(Debug, PartialEq)]
645    struct TestMyType(i32);
646
647    impl IntoInner for TestMyType {
648        type InnerType = i32;
649        fn into_inner(self) -> Self::InnerType {
650            self.0
651        }
652    }
653
654    impl TryNew for TestMyType {
655        type Error = TestMyTypeError;
656        fn try_new(value: i32) -> Result<Self, Self::Error> {
657            if value < 0 {
658                Err(TestMyTypeError("Value cannot be negative".to_string()))
659            } else {
660                Ok(TestMyType(value))
661            }
662        }
663    }
664
665    impl New for TestMyType {
666        fn new(value: i32) -> Self {
667            if value < 0 {
668                panic!("TestMyType::new: Value cannot be negative");
669            }
670            TestMyType(value)
671        }
672    }
673
674    mod conditionally_create {
675        use super::*;
676
677        #[test]
678        #[cfg(debug_assertions)] // This test specifically targets the debug behavior
679        fn test_positive_integer_conditionally_create_debug_ok() {
680            assert_eq!(
681                TestPositiveInteger::create_conditionally(10),
682                TestPositiveInteger { value: 10 }
683            );
684        }
685
686        #[test]
687        #[cfg(debug_assertions)] // This test specifically targets the debug behavior
688        #[should_panic(expected = "ConditionallyCreate: try_new() failed in debug mode")]
689        fn test_positive_integer_conditionally_create_debug_panic() {
690            TestPositiveInteger::create_conditionally(-5);
691        }
692
693        #[test]
694        #[cfg(not(debug_assertions))] // This test specifically targets the release behavior
695        fn test_positive_integer_conditionally_create_release_ok() {
696            assert_eq!(
697                TestPositiveInteger::create_conditionally(10),
698                TestPositiveInteger { value: 10 }
699            );
700        }
701
702        #[test]
703        #[cfg(not(debug_assertions))] // This test specifically targets the release behavior
704        #[should_panic(expected = "TestPositiveInteger::new: Value must be positive.")]
705        fn test_positive_integer_conditionally_create_release_panic() {
706            // In release, create_conditionally calls new(), which for TestPositiveInteger panics.
707            TestPositiveInteger::create_conditionally(-5);
708        }
709
710        #[test]
711        #[cfg(debug_assertions)]
712        fn test_my_type_conditionally_create_debug_ok() {
713            assert_eq!(TestMyType::create_conditionally(20), TestMyType(20));
714        }
715
716        #[test]
717        #[cfg(debug_assertions)]
718        #[should_panic(expected = "ConditionallyCreate: try_new() failed in debug mode")]
719        fn test_my_type_conditionally_create_debug_panic() {
720            TestMyType::create_conditionally(-3);
721        }
722
723        #[test]
724        #[cfg(not(debug_assertions))]
725        fn test_my_type_conditionally_create_release_ok() {
726            assert_eq!(TestMyType::create_conditionally(20), TestMyType(20));
727        }
728
729        #[test]
730        #[cfg(not(debug_assertions))]
731        #[should_panic(expected = "TestMyType::new: Value cannot be negative")]
732        fn test_my_type_conditionally_create_release_panic() {
733            TestMyType::create_conditionally(-3);
734        }
735    }
736
737    mod try_new_validated {
738        use super::*;
739
740        // --- Test setup for ValidationPolicy and TryNewValidated ---
741
742        // 1. Define a concrete ValidationPolicy
743        #[derive(Debug, PartialEq)]
744        struct TestPolicyError(String);
745
746        #[cfg(feature = "std")]
747        impl std::fmt::Display for TestPolicyError {
748            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
749                write!(f, "TestPolicyError: {}", self.0)
750            }
751        }
752
753        #[cfg(feature = "std")]
754        impl std::error::Error for TestPolicyError {}
755
756        struct MinValuePolicy {
757            min_value: i32,
758        }
759
760        impl ValidationPolicy for MinValuePolicy {
761            type Value = i32;
762            type Error = TestPolicyError;
763
764            fn validate_ref(v: &Self::Value) -> Result<(), Self::Error> {
765                // For this test, let's imagine a global or static policy.
766                // A real policy might take its configuration (e.g., min_value) at construction.
767                // For simplicity, we'll hardcode a value or use a fixed one.
768                // Let's make it simple: value must be >= 0 for this policy.
769                if *v >= 0 {
770                    Ok(())
771                } else {
772                    Err(TestPolicyError("Value must be non-negative.".to_string()))
773                }
774            }
775            // `validate` method uses the default implementation.
776        }
777
778        // 2. Define a concrete type that implements TryNewValidated
779
780        #[derive(Debug, PartialEq)]
781        enum TestValidatedTypeError {
782            Policy(TestPolicyError),
783            Construction(String),
784        }
785
786        #[cfg(feature = "std")]
787        impl std::fmt::Display for TestValidatedTypeError {
788            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
789                match self {
790                    TestValidatedTypeError::Policy(e) => write!(f, "Policy error: {}", e),
791                    TestValidatedTypeError::Construction(s) => {
792                        write!(f, "Construction error: {}", s)
793                    }
794                }
795            }
796        }
797
798        #[cfg(feature = "std")]
799        impl std::error::Error for TestValidatedTypeError {
800            fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
801                match self {
802                    TestValidatedTypeError::Policy(e) => Some(e),
803                    TestValidatedTypeError::Construction(_) => None,
804                }
805            }
806        }
807        // No-std: Debug is derived.
808
809        impl From<TestPolicyError> for TestValidatedTypeError {
810            fn from(e: TestPolicyError) -> Self {
811                TestValidatedTypeError::Policy(e)
812            }
813        }
814
815        #[derive(Debug, PartialEq)]
816        struct MyValidatedType {
817            value: i32,
818        }
819
820        impl IntoInner for MyValidatedType {
821            type InnerType = i32;
822            fn into_inner(self) -> Self::InnerType {
823                self.value
824            }
825        }
826
827        impl TryNew for MyValidatedType {
828            type Error = TestValidatedTypeError;
829
830            fn try_new(value: Self::InnerType) -> Result<Self, Self::Error> {
831                // Inner construction logic: value must be > 10
832                if value > 10 {
833                    Ok(MyValidatedType { value })
834                } else {
835                    Err(TestValidatedTypeError::Construction(
836                        "Value must be greater than 10 for construction.".to_string(),
837                    ))
838                }
839            }
840        }
841
842        impl TryNewValidated for MyValidatedType {
843            type Policy = MinValuePolicy; // Using the policy defined above
844
845            fn try_new_validated(value: <Self as IntoInner>::InnerType) -> Result<Self, Self::Error>
846            where
847                Self: Sized,
848                Self::Error: From<<Self::Policy as ValidationPolicy>::Error>,
849            {
850                // 1. Validate using the policy. The `?` handles error conversion.
851                Self::Policy::validate_ref(&value)?;
852
853                // 2. If policy validation passes, proceed with `try_new`.
854                Self::try_new(value)
855            }
856        }
857
858        // --- Tests for ValidationPolicy (using MinValuePolicy) ---
859        #[test]
860        fn validation_policy_validate_ref_ok() {
861            assert_eq!(MinValuePolicy::validate_ref(&5), Ok(()));
862            assert_eq!(MinValuePolicy::validate_ref(&0), Ok(()));
863        }
864
865        #[test]
866        fn validation_policy_validate_ref_err() {
867            assert_eq!(
868                MinValuePolicy::validate_ref(&-5),
869                Err(TestPolicyError("Value must be non-negative.".to_string()))
870            );
871        }
872
873        #[test]
874        fn validation_policy_validate_consuming_ok() {
875            // Tests the default `validate` method
876            assert_eq!(MinValuePolicy::validate(5), Ok(5));
877            assert_eq!(MinValuePolicy::validate(0), Ok(0));
878        }
879
880        #[test]
881        fn validation_policy_validate_consuming_err() {
882            // Tests the default `validate` method
883            assert_eq!(
884                MinValuePolicy::validate(-5),
885                Err(TestPolicyError("Value must be non-negative.".to_string()))
886            );
887        }
888
889        // --- Tests for TryNewValidated (using MyValidatedType) ---
890        #[test]
891        fn try_new_validated_success() {
892            // Policy (>=0) passes for 15. try_new (>10) passes for 15.
893            assert_eq!(
894                MyValidatedType::try_new_validated(15),
895                Ok(MyValidatedType { value: 15 })
896            );
897        }
898
899        #[test]
900        fn try_new_validated_policy_fail() {
901            // Policy (>=0) fails for -5.
902            let result = MyValidatedType::try_new_validated(-5);
903            assert!(matches!(result, Err(TestValidatedTypeError::Policy(..))));
904        }
905
906        #[test]
907        fn try_new_validated_construction_fail_after_policy_pass() {
908            // Policy (>=0) passes for 5. try_new (>10) fails for 5.
909            let result = MyValidatedType::try_new_validated(5);
910            assert!(matches!(
911                result,
912                Err(TestValidatedTypeError::Construction(..))
913            ));
914        }
915
916        #[test]
917        fn try_new_validated_policy_pass_construction_pass_edge() {
918            // Policy (>=0) passes for 11. try_new (>10) passes for 11.
919            assert_eq!(
920                MyValidatedType::try_new_validated(11),
921                Ok(MyValidatedType { value: 11 })
922            );
923        }
924
925        #[test]
926        fn try_new_validated_policy_pass_construction_fail_edge() {
927            // Policy (>=0) passes for 10. try_new (>10) fails for 10.
928            let result = MyValidatedType::try_new_validated(10);
929            assert!(matches!(
930                result,
931                Err(TestValidatedTypeError::Construction(..))
932            ));
933        }
934    }
935}