use crate::prelude::*; use crate::rail_connector::RailConnector; use std::error; use std::fmt; use std::iter::Iterator; #[derive(Debug)] pub enum Error { IndexError(usize), EndpointError(usize), OffsetError(f32), ConnectionError(usize), StateError(f32), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::IndexError(index) => write!(f, "Nonexistent sub-segment index: {index}."), Self::EndpointError(endpoint) => write!(f, "Nonexistent endpoint index: {endpoint}."), Self::OffsetError(offset) => write!(f, "Invalid offset: {offset}."), Self::ConnectionError(endpoint) => write!(f, "Endpoint {endpoint} is not connected."), Self::StateError(state) => write!(f, "Invalid state: {state}."), } } } impl error::Error for Error {} pub struct ConnectionIter<'a> { segment: &'a dyn RailSegment, index: usize, } impl<'a> ConnectionIter<'a> { pub fn new(segment: &'a impl RailSegment) -> Self { Self { segment, index: 0, } } } impl<'a> Iterator for ConnectionIter<'a> { type Item = &'a RailConnector; fn next(&mut self) -> Option { while self.index < self.segment.num_endpoints() { if let Ok(connection) = self.segment.borrow_connection(self.index) { self.index += 1; return Some(connection); } else { self.index += 1; } } return None; } } /** A RailSegment represents a section of track. * They contain at least one internal curve which is addressibe via an integer * index. Valid indecies start at 0, though a negative index may be used to * indicate that a point does not exist on any internal curve. Offsets are in * Godot units (which shall be interpreted as meters). */ pub trait RailSegment { /** Get the overall length of the internal curve represented by the given * `index`. */ fn get_length(&self, index: usize) -> Result; /** Get the location defined by the given `offset` on the internal curve * represented by the given `index`. */ fn sample(&self, index: usize, offset: f32) -> Result; /** Get the location defined by the given `offset` on the internal curve * represented by the given `index`, but with additional rotation data. */ fn sample_with_rotation(&self, index: usize, offset: f32) -> Result; /** Similar to sample_with_rotation, but the rotation is facing the opposite direction. */ fn sample_with_rotation_reverse(&self, index: usize, offset: f32) -> Result; /** Get the direction that constitutes "up" for the given `offset` on the * internal curve represented by the given `index`. */ fn sample_up_vector(&self, index: usize, offset: f32) -> Result; // endpoint functions /** Get the segment index associated with an endpoint. */ fn segment_from_endpoint(&self, endpoint: usize) -> Result; /** Get the location of an endpoint. */ fn get_endpoint_transform(&self, endpoint: usize) -> Result; /** Get whether an endpoint represents the upper or lower end of a segment. */ fn is_endpoint_upper(&self, endpoint: usize) -> Result; /** Get the number of endpoins this segment has. */ fn num_endpoints(&self) -> usize; // connection functions /** Borrow the connector associated with the given endpoint. */ fn borrow_connection(&self, endpoint: usize) -> Result<&RailConnector, Error>; /** Copy the connector associated with the given endpoint. */ fn get_connection(&self, endpoint: usize) -> Result; /** Check if a connection is established on the given endpoint. */ fn check_connection(&self, endpoint: usize) -> Result; /** Get an iterator of the connections on this segment. * If an endpoint is not connected, then it will not be represented by this iterator. * This iterator keeps an immutable reference to the segment from which it was created. */ fn connection_iter(&self) -> ConnectionIter; /** Add a connection to the given endpoint. * Any previous connection on it is overwritten. */ fn add_connection(&mut self, endpoint: usize, connector: RailConnector) -> Result; /** Remove the given endpoint's connection if it has one. */ fn remove_connection(&mut self, endpoint: usize) -> Result; /** Remove all connections from the segment. */ fn remove_all_connections(&mut self); // internal variable state functions /** Get the internal state float value. */ fn get_state(&self) -> f32; /** Set the internal state float value. */ fn set_state(&mut self, value: f32) -> Result; }