use crate::types::{DateRange, Limit, Page};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum GeographicAvailability {
Worldwide,
UsOnly,
#[default]
Unspecified,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum AccessRequirement {
Standard,
NamedAddOn(&'static str),
#[default]
Unspecified,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum PlanCondition {
HistoryOlderThanYears(u16),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ConditionalPlanRequirement {
plan: &'static str,
condition: PlanCondition,
}
impl ConditionalPlanRequirement {
pub const fn new(plan: &'static str, condition: PlanCondition) -> Self {
Self { plan, condition }
}
pub const fn plan(self) -> &'static str {
self.plan
}
pub const fn condition(self) -> PlanCondition {
self.condition
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum UserDeclarationRequirement {
RequiredForRealtime,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct RealtimeAccess {
delay: Option<MarketDataDelay>,
user_declaration: Option<UserDeclarationRequirement>,
}
impl RealtimeAccess {
pub const fn new(
delay: Option<MarketDataDelay>,
user_declaration: Option<UserDeclarationRequirement>,
) -> Self {
Self {
delay,
user_declaration,
}
}
pub const fn delay(self) -> Option<MarketDataDelay> {
self.delay
}
pub const fn user_declaration(self) -> Option<UserDeclarationRequirement> {
self.user_declaration
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum DelayScope {
Nasdaq,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MarketDataDelay {
minutes: u16,
scope: DelayScope,
}
impl MarketDataDelay {
pub const fn new(minutes: u16, scope: DelayScope) -> Self {
Self { minutes, scope }
}
pub const fn minutes(self) -> u16 {
self.minutes
}
pub const fn scope(self) -> DelayScope {
self.scope
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InclusiveMaximum(u32);
impl InclusiveMaximum {
pub const fn new(maximum: u32) -> Self {
Self(maximum)
}
pub const fn maximum(self) -> u32 {
self.0
}
pub const fn contains(self, value: u32) -> bool {
value <= self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct EndpointBounds {
limit: Option<InclusiveMaximum>,
response_rows: Option<InclusiveMaximum>,
page: Option<InclusiveMaximum>,
date_range_days: Option<InclusiveMaximum>,
}
impl EndpointBounds {
pub const fn new() -> Self {
Self {
limit: None,
response_rows: None,
page: None,
date_range_days: None,
}
}
pub const fn with_limit(mut self, maximum: u32) -> Self {
self.limit = Some(InclusiveMaximum::new(maximum));
self
}
pub const fn with_response_rows(mut self, maximum: u32) -> Self {
self.response_rows = Some(InclusiveMaximum::new(maximum));
self
}
pub const fn with_page(mut self, maximum: u32) -> Self {
self.page = Some(InclusiveMaximum::new(maximum));
self
}
pub const fn with_date_range_days(mut self, maximum: u32) -> Self {
self.date_range_days = Some(InclusiveMaximum::new(maximum));
self
}
pub const fn limit(self) -> Option<InclusiveMaximum> {
self.limit
}
pub const fn response_rows(self) -> Option<InclusiveMaximum> {
self.response_rows
}
pub const fn page(self) -> Option<InclusiveMaximum> {
self.page
}
pub const fn date_range_days(self) -> Option<InclusiveMaximum> {
self.date_range_days
}
pub const fn accepts_limit(self, value: Limit) -> bool {
match self.limit {
Some(maximum) => maximum.contains(value.0),
None => true,
}
}
pub const fn accepts_response_rows(self, value: u32) -> bool {
match self.response_rows {
Some(maximum) => maximum.contains(value),
None => true,
}
}
pub const fn accepts_page(self, value: Page) -> bool {
match self.page {
Some(maximum) => maximum.contains(value.0),
None => true,
}
}
pub fn accepts_date_range(self, value: &DateRange) -> bool {
match self.date_range_days {
Some(maximum) => maximum.contains(value.span_days() as u32),
None => true,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct EndpointMetadata {
geography: GeographicAvailability,
access: AccessRequirement,
conditional_plan: Option<ConditionalPlanRequirement>,
realtime: Option<RealtimeAccess>,
bounds: EndpointBounds,
}
impl EndpointMetadata {
pub const fn new() -> Self {
Self {
geography: GeographicAvailability::Unspecified,
access: AccessRequirement::Unspecified,
conditional_plan: None,
realtime: None,
bounds: EndpointBounds::new(),
}
}
pub const fn with_geography(mut self, geography: GeographicAvailability) -> Self {
self.geography = geography;
self
}
pub const fn with_access(mut self, access: AccessRequirement) -> Self {
self.access = access;
self
}
pub const fn with_conditional_plan(mut self, requirement: ConditionalPlanRequirement) -> Self {
self.conditional_plan = Some(requirement);
self
}
pub const fn with_realtime(mut self, realtime: RealtimeAccess) -> Self {
self.realtime = Some(realtime);
self
}
pub const fn with_bounds(mut self, bounds: EndpointBounds) -> Self {
self.bounds = bounds;
self
}
pub const fn geography(self) -> GeographicAvailability {
self.geography
}
pub const fn access(self) -> AccessRequirement {
self.access
}
pub const fn conditional_plan(self) -> Option<ConditionalPlanRequirement> {
self.conditional_plan
}
pub const fn realtime(self) -> Option<RealtimeAccess> {
self.realtime
}
pub const fn bounds(self) -> EndpointBounds {
self.bounds
}
}