Skip to main content

ContractIdParts

Struct ContractIdParts 

Source
pub struct ContractIdParts {
    pub country_code: String,
    pub provider_id: String,
    pub instance: String,
    pub check_digit: Option<char>,
}
Expand description

The parts of an eMI3/IDACS Contract ID (eMAID), when it follows the recommended format.

Recommended to follow the specification for eMA ID from “E-mobility ID-codes: the purpose of IDs, ID usage and ID format”.

The format is <country><provider><instance>[<check>]: two letters, three alphanumerics, nine alphanumerics, and an optional check character. A hyphen may separate all three positions — “if the hyphenated representation is chosen, the separators must be set at all three places” — and is for human reading only; the IDACS white paper advises against sending it between systems.

This is what makes a whitelist match. contract_id is a CiString, so case already does not matter, but DE-8AA-CA2B3C4D5-N and DE8AACA2B3C4D5N are the same contract written two ways, and comparing the strings says they are not. normalise folds both to one key.

Like EvseIdParts, parsing is a query rather than a requirement: the format is recommended by OCPI, not mandated, so an id in any other shape returns None and the crate carries on.

§What this cannot tell you

The format has no marker to match on — it is “two letters, then twelve or thirteen alphanumerics” — so any id of that shape parses, including one that is not an eMAID at all. some-internal-id is fourteen characters once the hyphens go, and comes back as a contract in SO issued by provider MEI.

That costs a whitelist nothing, because normalise is a function: the same id always folds to the same key, whether or not it was really an eMAID. It does mean party is only meaningful for an id you already know follows the format. The instance conventionally begins with C“strongly recommended to use the type-ID C as first character” — which is a useful signal, but a recommendation is not something this crate will reject a conformant id over.

use ocpi_kit::types::ContractIdParts;

let parts = ContractIdParts::parse("DE-8AA-CA2B3C4D5-N").unwrap();
assert_eq!(parts.country_code, "DE");
assert_eq!(parts.provider_id, "8AA");
assert_eq!(parts.instance, "CA2B3C4D5");
assert_eq!(parts.check_digit, Some('N'));

// The same contract, written three ways, folds to one key.
let key = ContractIdParts::normalise("DE-8AA-CA2B3C4D5-N").unwrap();
assert_eq!(key, "DE8AACA2B3C4D5N");
assert_eq!(ContractIdParts::normalise("de8aaca2b3c4d5n").unwrap(), key);
assert_eq!(ContractIdParts::normalise("DE*8AA*CA2B3C4D5*N").unwrap(), key);

// Anything not of that shape is `None`, and so is anything too short or too long.
assert!(ContractIdParts::parse("DE8AA").is_none());
assert!(ContractIdParts::parse("12-8AA-CA2B3C4D5-N").is_none()); // country is not letters

Spec: 2.3.0 §mod_cdrs_cdr_token_class, §mod_tokens_token_object

Fields§

§country_code: String

The two-letter ISO 3166-1 alpha-2 country code of the provider.

§provider_id: String

The three-character provider ID, assigned by the eMI3 group.

§instance: String

The nine-character instance, whose first character is conventionally C.

§check_digit: Option<char>

The check character, which the format marks optional.

Implementations§

Source§

impl ContractIdParts

Source

pub fn parse(id: &str) -> Option<Self>

Parses an eMI3/IDACS contract ID, or returns None if id is in another shape.

Both separators seen in the field are accepted — -, which the contract-ID format specifies, and *, which the EVSE-ID format uses and which some platforms carry over.

Source

pub fn normalise(id: &str) -> Option<String>

The one key two spellings of the same contract share: upper case, no separators.

This is the form to key a whitelist on. Returns None for an id that does not follow the format, which a caller should treat as “not comparable” rather than as “no match” — an eMSP is free to use its own scheme.

Source

pub fn party(&self) -> Result<PartyRef, InvalidString>

The provider that issued this contract, according to the ID.

As with EvseIdParts::party, this need not be the OCPI party_id that pushed the object: “The party_id and country_code given here have no direct link with the eMI3/IDACS format EVSE IDs and Contract IDs.”

§Errors

Returns InvalidString if the parts are not valid CiStrings, which cannot happen for a value that came out of ContractIdParts::parse.

Source

pub fn to_compact(&self) -> String

The ID with no separators and in upper case: DE8AACA2B3C4D5N.

Companies are strongly advised NOT to use the optional separators between IT systems as they are meant for visibility only.

Source

pub fn to_separated(&self) -> String

The ID in the hyphenated form a human reads: DE-8AA-CA2B3C4D5-N.

Trait Implementations§

Source§

impl Clone for ContractIdParts

Source§

fn clone(&self) -> ContractIdParts

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ContractIdParts

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for ContractIdParts

Source§

impl PartialEq for ContractIdParts

Source§

fn eq(&self, other: &ContractIdParts) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for ContractIdParts

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more