Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Impressum iso8601.rs

  Sprache: Rust
 

//! Parse parts of an ISO 8601-formatted value.

use num_conv::prelude::*;

use crate::convert::*;
use crate::error;
use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral};
use crate::format_description::well_known::iso8601::EncodedConfig;
use crate::format_description::well_known::Iso8601;
use crate::parsing::combinator::rfc::iso8601::{
    day, dayk, dayo, float, hour, min, month, week, year, ExtendedKind,
};
use crate::parsing::combinator::{ascii_char, sign};
use crate::parsing::{Parsed, ParsedItem};

impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
    // Basic: [year][month][day]
    // Extended: [year]["-"][month]["-"][day]
    // Basic: [year][dayo]
    // Extended: [year]["-"][dayo]
    // Basic: [year]["W"][week][dayk]
    // Extended: [year]["-"]["W"][week]["-"][dayk]
    /// Parse a date in the basic or extended format. Reduced precision is permitted.
    pub(cratefn parse_date<'a>(
        parsed: &'a mut Parsed,
        extended_kind: &'a mut ExtendedKind,
    ) -> impl FnMut(&[u8]) -> Result<&[u8], error::Parse> + 'a {
        move |input| {
            // Same for any acceptable format.
            let ParsedItem(mut input, year) = year(input).ok_or(InvalidComponent("year"))?;
            *extended_kind = match ascii_char::<b'-'>(input) {
                Some(ParsedItem(new_input, ())) => {
                    input = new_input;
                    ExtendedKind::Extended
                }
                None => ExtendedKind::Basic, // no separator before mandatory month/ordinal/week
            };

            let parsed_month_day = (|| {
                let ParsedItem(mut input, month) = month(input).ok_or(InvalidComponent("month"))?;
                if extended_kind.is_extended() {
                    input = ascii_char::<b'-'>(input)
                        .ok_or(InvalidLiteral)?
                        .into_inner();
                }
                let ParsedItem(input, day) = day(input).ok_or(InvalidComponent("day"))?;
                Ok(ParsedItem(input, (month, day)))
            })();
            let mut ret_error = match parsed_month_day {
                Ok(ParsedItem(input, (month, day))) => {
                    *parsed = parsed
                        .with_year(year)
                        .ok_or(InvalidComponent("year"))?
                        .with_month(month)
                        .ok_or(InvalidComponent("month"))?
                        .with_day(day)
                        .ok_or(InvalidComponent("day"))?;
                    return Ok(input);
                }
                Err(err) => err,
            };

            // Don't check for `None`, as the error from year-month-day will always take priority.
            if let Some(ParsedItem(input, ordinal)) = dayo(input) {
                *parsed = parsed
                    .with_year(year)
                    .ok_or(InvalidComponent("year"))?
                    .with_ordinal(ordinal)
                    .ok_or(InvalidComponent("ordinal"))?;
                return Ok(input);
            }

            let parsed_week_weekday = (|| {
                let input = ascii_char::<b'W'>(input)
                    .ok_or((false, InvalidLiteral))?
                    .into_inner();
                let ParsedItem(mut input, week) =
                    week(input).ok_or((true, InvalidComponent("week")))?;
                if extended_kind.is_extended() {
                    input = ascii_char::<b'-'>(input)
                        .ok_or((true, InvalidLiteral))?
                        .into_inner();
                }
                let ParsedItem(input, weekday) =
                    dayk(input).ok_or((true, InvalidComponent("weekday")))?;
                Ok(ParsedItem(input, (week, weekday)))
            })();
            match parsed_week_weekday {
                Ok(ParsedItem(input, (week, weekday))) => {
                    *parsed = parsed
                        .with_iso_year(year)
                        .ok_or(InvalidComponent("year"))?
                        .with_iso_week_number(week)
                        .ok_or(InvalidComponent("week"))?
                        .with_weekday(weekday)
                        .ok_or(InvalidComponent("weekday"))?;
                    return Ok(input);
                }
                Err((false, _err)) => {}
                // This error is more accurate than the one from year-month-day.
                Err((true, err)) => ret_error = err,
            }

            Err(ret_error.into())
        }
    }

    // Basic: ["T"][hour][min][sec]
    // Extended: ["T"][hour][":"][min][":"][sec]
    // Reduced precision: components after [hour] (including their preceding separator) can be
    // omitted. ["T"] can be omitted if there is no date present.
    /// Parse a time in the basic or extended format. Reduced precision is permitted.
    pub(cratefn parse_time<'a>(
        parsed: &'a mut Parsed,
        extended_kind: &'a mut ExtendedKind,
        date_is_present: bool,
    ) -> impl FnMut(&[u8]) -> Result<&[u8], error::Parse> + 'a {
        move |mut input| {
            if date_is_present {
                input = ascii_char::<b'T'>(input)
                    .ok_or(InvalidLiteral)?
                    .into_inner();
            }

            let ParsedItem(mut input, hour) = float(input).ok_or(InvalidComponent("hour"))?;
            match hour {
                (hour, None) => parsed.set_hour_24(hour).ok_or(InvalidComponent("hour"))?,
                (hour, Some(fractional_part)) => {
                    *parsed = parsed
                        .with_hour_24(hour)
                        .ok_or(InvalidComponent("hour"))?
                        .with_minute((fractional_part * Second::per(Minute) as f64) as _)
                        .ok_or(InvalidComponent("minute"))?
                        .with_second(
                            (fractional_part * Second::per(Hour) as f64 % Minute::per(Hour) as f64)
                                as _,
                        )
                        .ok_or(InvalidComponent("second"))?
                        .with_subsecond(
                            (fractional_part * Nanosecond::per(Hour) as f64
                                % Nanosecond::per(Second) as f64) as _,
                        )
                        .ok_or(InvalidComponent("subsecond"))?;
                    return Ok(input);
                }
            };

            if let Some(ParsedItem(new_input, ())) = ascii_char::<b':'>(input) {
                extended_kind
                    .coerce_extended()
                    .ok_or(InvalidComponent("minute"))?;
                input = new_input;
            };

            let mut input = match float(input) {
                Some(ParsedItem(input, (minute, None))) => {
                    extended_kind.coerce_basic();
                    parsed
                        .set_minute(minute)
                        .ok_or(InvalidComponent("minute"))?;
                    input
                }
                Some(ParsedItem(input, (minute, Some(fractional_part)))) => {
                    // `None` is valid behavior, so don't error if this fails.
                    extended_kind.coerce_basic();
                    *parsed = parsed
                        .with_minute(minute)
                        .ok_or(InvalidComponent("minute"))?
                        .with_second((fractional_part * Second::per(Minute) as f64) as _)
                        .ok_or(InvalidComponent("second"))?
                        .with_subsecond(
                            (fractional_part * Nanosecond::per(Minute) as f64
                                % Nanosecond::per(Second) as f64) as _,
                        )
                        .ok_or(InvalidComponent("subsecond"))?;
                    return Ok(input);
                }
                // colon was present, so minutes are required
                None if extended_kind.is_extended() => {
                    return Err(error::Parse::ParseFromDescription(InvalidComponent(
                        "minute",
                    )));
                }
                None => {
                    // Missing components are assumed to be zero.
                    *parsed = parsed
                        .with_minute(0)
                        .ok_or(InvalidComponent("minute"))?
                        .with_second(0)
                        .ok_or(InvalidComponent("second"))?
                        .with_subsecond(0)
                        .ok_or(InvalidComponent("subsecond"))?;
                    return Ok(input);
                }
            };

            if extended_kind.is_extended() {
                match ascii_char::<b':'>(input) {
                    Some(ParsedItem(new_input, ())) => input = new_input,
                    None => {
                        *parsed = parsed
                            .with_second(0)
                            .ok_or(InvalidComponent("second"))?
                            .with_subsecond(0)
                            .ok_or(InvalidComponent("subsecond"))?;
                        return Ok(input);
                    }
                }
            }

            let (input, second, subsecond) = match float(input) {
                Some(ParsedItem(input, (second, None))) => (input, second, 0),
                Some(ParsedItem(input, (second, Some(fractional_part)))) => (
                    input,
                    second,
                    round(fractional_part * Nanosecond::per(Second) as f64) as _,
                ),
                None if extended_kind.is_extended() => {
                    return Err(error::Parse::ParseFromDescription(InvalidComponent(
                        "second",
                    )));
                }
                // Missing components are assumed to be zero.
                None => (input, 00),
            };
            *parsed = parsed
                .with_second(second)
                .ok_or(InvalidComponent("second"))?
                .with_subsecond(subsecond)
                .ok_or(InvalidComponent("subsecond"))?;

            Ok(input)
        }
    }

    // Basic: [±][hour][min] or ["Z"]
    // Extended: [±][hour][":"][min] or ["Z"]
    // Reduced precision: [±][hour] or ["Z"]
    /// Parse a UTC offset in the basic or extended format. Reduced precision is supported.
    pub(cratefn parse_offset<'a>(
        parsed: &'a mut Parsed,
        extended_kind: &'a mut ExtendedKind,
    ) -> impl FnMut(&[u8]) -> Result<&[u8], error::Parse> + 'a {
        move |input| {
            if let Some(ParsedItem(input, ())) = ascii_char::<b'Z'>(input) {
                *parsed = parsed
                    .with_offset_hour(0)
                    .ok_or(InvalidComponent("offset hour"))?
                    .with_offset_minute_signed(0)
                    .ok_or(InvalidComponent("offset minute"))?
                    .with_offset_second_signed(0)
                    .ok_or(InvalidComponent("offset second"))?;
                return Ok(input);
            }

            let ParsedItem(input, sign) = sign(input).ok_or(InvalidComponent("offset hour"))?;
            let mut input = hour(input)
                .and_then(|parsed_item| {
                    parsed_item.consume_value(|hour| {
                        parsed.set_offset_hour(if sign == b'-' {
                            -hour.cast_signed()
                        } else {
                            hour.cast_signed()
                        })
                    })
                })
                .ok_or(InvalidComponent("offset hour"))?;

            if extended_kind.maybe_extended() {
                if let Some(ParsedItem(new_input, ())) = ascii_char::<b':'>(input) {
                    extended_kind
                        .coerce_extended()
                        .ok_or(InvalidComponent("offset minute"))?;
                    input = new_input;
                };
            }

            match min(input) {
                Some(ParsedItem(new_input, min)) => {
                    input = new_input;
                    parsed
                        .set_offset_minute_signed(if sign == b'-' {
                            -min.cast_signed()
                        } else {
                            min.cast_signed()
                        })
                        .ok_or(InvalidComponent("offset minute"))?;
                }
                None => {
                    // Omitted offset minute is assumed to be zero.
                    parsed.set_offset_minute_signed(0);
                }
            }

            // If `:` was present, the format has already been set to extended. As such, this call
            // will do nothing in that case. If there wasn't `:` but minutes were
            // present, we know it's the basic format. Do not use `?` on the call, as
            // returning `None` is valid behavior.
            extended_kind.coerce_basic();

            Ok(input)
        }
    }
}

/// Round wrapper that uses hardware implementation if `std` is available, falling back to manual
/// implementation for `no_std`
fn round(value: f64) -> f64 {
    #[cfg(feature = "std")]
    {
        value.round()
    }
    #[cfg(not(feature = "std"))]
    {
        round_impl(value)
    }
}

#[cfg(not(feature = "std"))]
#[allow(clippy::missing_docs_in_private_items)]
fn round_impl(value: f64) -> f64 {
    debug_assert!(value.is_sign_positive() && !value.is_nan());

    let f = value % 1.;
    if f < 0.5 { value - f } else { value - f + 1. }
}

Messung V0.5 in Prozent
C=91 H=100 G=95

¤ Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.0.18Bemerkung:  (vorverarbeitet am  2026-06-28) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik