use super::*;
#[cfg(test)]
mod authoring_helpers_tests;
pub trait IntoSceneOutput {
fn into_scene_output(self) -> crate::Result<Node>;
}
impl<Output: Into<Node>> IntoSceneOutput for Output {
fn into_scene_output(self) -> crate::Result<Node> {
Ok(self.into())
}
}
impl<Output: Into<Node>, Failure: Into<crate::Error>> IntoSceneOutput
for std::result::Result<Output, Failure>
{
fn into_scene_output(self) -> crate::Result<Node> {
self.map(Into::into).map_err(Into::into)
}
}
struct SceneFailure {
error: Arc<crate::Error>,
}
impl SceneFailure {
fn new(error: crate::Error) -> Self {
Self {
error: Arc::new(error),
}
}
fn diagnostic(&self, context: &DrawContext) -> ValidationError {
context.diagnostics().record_scene(self.error.clone());
if let Some(error) = self.error.downcast_ref::<ValidationError>() {
return error.clone();
}
ValidationError::invalid("scene", "output", self.error.to_string())
}
}
pub(crate) fn failure(error: impl Into<crate::Error>) -> Node {
Node::from(SceneFailure::new(error.into()))
}
impl Drawable for SceneFailure {
fn bounds(&self, context: &DrawContext) -> Result<Rect, ValidationError> {
Err(self.diagnostic(context))
}
fn draw(
&self,
context: &DrawContext,
_: &mut crate::Canvas<'_>,
) -> Result<(), ValidationError> {
Err(self.diagnostic(context))
}
}
pub fn scene<Build, Output>(build: Build) -> impl Fn(&SceneContext<'_>) -> Node + Send + Sync
where
Build: Fn(&SceneContext<'_>) -> Output + Send + Sync,
Output: IntoSceneOutput,
{
move |context| match build(context).into_scene_output() {
Ok(node) => node,
Err(error) => {
let failure = SceneFailure::new(error);
context.diagnostics().record_scene(failure.error.clone());
Node::from(failure)
}
}
}
#[macro_export]
macro_rules! group {
() => { $crate::Node::empty() };
($($child:expr),* $(,)?) => {
$crate::Node::group([$($crate::Node::from($child)),*])
};
}
pub trait Scene: Send + Sync {
fn validate(&self) -> crate::Result<()> {
Ok(())
}
fn render(&self, context: &SceneContext<'_>) -> Node;
fn duration(&self) -> Option<Duration> {
None
}
fn with_duration(self, duration: Duration) -> WithDuration<Self>
where
Self: Sized,
{
WithDuration {
scene: self,
duration,
}
}
}
impl<Callback> Scene for Callback
where
Callback: Fn(&SceneContext<'_>) -> Node + Send + Sync,
{
fn render(&self, context: &SceneContext<'_>) -> Node {
self(context)
}
}
impl Scene for Arc<dyn Scene> {
fn validate(&self) -> crate::Result<()> {
self.as_ref().validate()
}
fn render(&self, context: &SceneContext<'_>) -> Node {
self.as_ref().render(context)
}
fn duration(&self) -> Option<Duration> {
self.as_ref().duration()
}
}
pub struct WithDuration<Content> {
scene: Content,
duration: Duration,
}
impl<Content: Scene> Scene for WithDuration<Content> {
fn validate(&self) -> crate::Result<()> {
self.scene.validate()
}
fn render(&self, context: &SceneContext<'_>) -> Node {
self.scene.render(context)
}
fn duration(&self) -> Option<Duration> {
Some(self.duration)
}
}