terrazzo-terminal 0.2.7

A simple web-based terminal emulator built on Terrazzo.
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
use std::task::ready;

use pin_project::pin_project;
use server_fn::ServerFnError;

use super::HybridResponseStream;
use super::HybridResponseStreamProj;
use crate::backend::protos::terrazzo::notify::NotifyResponse as NotifyResponseProto;
use crate::backend::protos::terrazzo::notify::notify_response;
use crate::backend::protos::terrazzo::notify::notify_response::FileEventKind as FileEventKindProto;
use crate::text_editor::notify::server_fn::EventKind;
use crate::text_editor::notify::server_fn::FileEventKind;
use crate::text_editor::notify::server_fn::NotifyResponse;
use crate::utils::more_path::MorePath as _;

#[pin_project(project = RemoteReaderProj)]
pub struct RemoteResponseStream(#[pin] pub HybridResponseStream);

impl futures::Stream for RemoteResponseStream {
    type Item = Result<NotifyResponseProto, tonic::Status>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        match self.project().0.project() {
            HybridResponseStreamProj::Local(this) => {
                poll_next_remote(ready!(this.as_mut().poll_next(cx))).into()
            }
            HybridResponseStreamProj::Remote(this) => this.poll_next(cx),
        }
    }
}

fn poll_next_remote(
    response: Option<Result<NotifyResponse, ServerFnError>>,
) -> Option<Result<NotifyResponseProto, tonic::Status>> {
    Some(poll_next_remote_some(response?))
}

fn poll_next_remote_some(
    response: Result<NotifyResponse, ServerFnError>,
) -> Result<NotifyResponseProto, tonic::Status> {
    let response =
        response.map_err(|error| tonic::Status::internal(format!("Remote error: {error}")))?;
    let event_kind = match response.kind {
        EventKind::File(kind) => notify_response::Kind::File(
            match kind {
                FileEventKind::Create => FileEventKindProto::Create,
                FileEventKind::Modify => FileEventKindProto::Modify,
                FileEventKind::Delete => FileEventKindProto::Delete,
                FileEventKind::Error => FileEventKindProto::Error,
            }
            .into(),
        ),
        EventKind::CargoCheck(diagnostics) => notify_response::Kind::CargoCheck(
            serde_json::to_string(&diagnostics)
                .map_err(|error| tonic::Status::internal(format!("JSON error: {error}")))?,
        ),
    };
    Ok(NotifyResponseProto {
        path: response.path.as_ref().to_owned_string(),
        kind: event_kind.into(),
    })
}