New Unchecked - parsicore/parsidate GitHub Wiki
ParsiDate::new_unchecked
Constructor (unsafe) Creates a new ParsiDate
instance from year, month, and day components without performing any validation.
⚠️ Warning: Unsafe Operation ⚠️
This function is marked unsafe
because it completely bypasses the validation checks normally performed by the safe ParsiDate::new
constructor.
- If you provide invalid components (e.g.,
month = 13
,day = 32
,day = 30
for Esfand in a common year,year = 0
,year = 10000
), this function will still create aParsiDate
instance containing that invalid data. - Subsequent operations on such an invalid
ParsiDate
instance (like formatting, comparison, arithmetic, or even simple getters if they rely on internal consistency) can lead to unpredictable behavior, incorrect results, logic errors, or runtime panics.
Do not use this function unless you meet the following conditions:
- You have already rigorously validated the
year
,month
, andday
components through external means before calling this function. - You have an absolute performance requirement that necessitates skipping the validation overhead of
ParsiDate::new
.
In nearly all typical use cases, the safe ParsiDate::new
constructor is the strongly preferred and recommended choice.
Safety Contract
The caller MUST guarantee that the provided year
, month
, and day
combination:
- Represents a logically valid date within the rules of the Persian (Hejri-Shamsi) calendar. This includes:
month
is between 1 and 12 (inclusive).day
is between 1 and the correct number of days for the givenmonth
andyear
(considering 31 days for months 1-6, 30 days for months 7-11, and 29 or 30 days for month 12 based on whetheryear
is leap).
- The
year
is within the supported range of this library (e.g.,[1, 9999]
).
Failure to uphold this guarantee violates the safety contract and invokes undefined behavior from the perspective of this library's date logic, potentially leading to the issues mentioned in the warning above.
Arguments
year
(i32
or similar integer type): The year component. Must be pre-validated by the caller.month
(u8
or similar integer type): The month component. Must be pre-validated by the caller.day
(u8
or similar integer type): The day component. Must be pre-validated by the caller.
Returns
- A
ParsiDate
instance containing the providedyear
,month
, andday
, regardless of whether they form a valid date.
Examples (Rust)
use parsidate::{ParsiDate, DateError}; // Assuming ParsiDate struct and potentially helpers
// --- !!! Incorrect Usage Example !!! ---
// DO NOT DO THIS unless you are 100% certain of validity elsewhere.
// Creating an invalid date (Esfand 30 in a common year 1404)
// let invalid_date = unsafe { ParsiDate::new_unchecked(1404, 12, 30) };
// Even though ParsiDate::new(1404, 12, 30) would return Err,
// new_unchecked creates the object.
// assert!(!invalid_date.is_valid()); // Checking validity later confirms it's bad.
// Using invalid_date further could lead to panics or incorrect results.
// --- Correct Usage Example (with Prior Validation) ---
// Assume these components have been pre-validated by some robust external logic
let p_year = 1403; // A leap year
let p_month = 12; // Esfand
let p_day = 30; // Valid day for Esfand in 1403
// Example of a hypothetical external validation function
// In reality, use a proper date validation library or ParsiDate::new itself
// if performance isn't the absolute bottleneck.
fn is_known_valid(y: i32, m: u8, d: u8) -> bool {
// This is a simplified check; a real one needs ParsiDate::days_in_month logic
// or use the result of ParsiDate::new(y, m, d).is_ok()
const MIN_YEAR: i32 = 1;
const MAX_YEAR: i32 = 9999; // Use the actual library constants if available
if !(MIN_YEAR..=MAX_YEAR).contains(&y) || !(1..=12).contains(&m) || d < 1 {
return false;
}
// A real check needs ParsiDate::days_in_month(y, m)
let max_days = if m <= 6 { 31 } else if m <= 11 { 30 } else {
if ParsiDate::is_persian_leap_year(y) { 30 } else { 29 }
};
d <= max_days
}
// Only call new_unchecked if the validation passed
if is_known_valid(p_year, p_month, p_day) {
println!("Validation passed, proceeding with unsafe construction.");
// It's now considered safe to use new_unchecked because the caller
// has upheld the safety contract.
let date = unsafe { ParsiDate::new_unchecked(p_year, p_month, p_day) };
// Verify the components were stored
assert_eq!(date.year(), 1403);
assert_eq!(date.month(), 12);
assert_eq!(date.day(), 30);
assert!(date.is_valid()); // Should pass if is_known_valid is correct
} else {
// If validation failed, DO NOT call new_unchecked.
eprintln!("Validation failed for year={}, month={}, day={}. Cannot use new_unchecked.", p_year, p_month, p_day);
// Handle the error appropriately (e.g., return Err, panic, log).
// For demonstration, we just print. In real code, you'd likely return an error.
// For instance: return Err(DateError::InvalidDate);
}
// Example with different valid data
let p_year2 = 1404; // Common year
let p_month2 = 7; // Mehr
let p_day2 = 30; // Last day of Mehr
if is_known_valid(p_year2, p_month2, p_day2) {
let date2 = unsafe { ParsiDate::new_unchecked(p_year2, p_month2, p_day2) };
assert_eq!(date2.year(), 1404);
assert_eq!(date2.month(), 7);
assert_eq!(date2.day(), 30);
assert!(date2.is_valid());
} else {
eprintln!("Validation failed for year={}, month={}, day={}.", p_year2, p_month2, p_day2);
}