dap_command.rs

   1use std::sync::Arc;
   2
   3use anyhow::{Context as _, Ok, Result};
   4use base64::Engine;
   5use dap::{
   6    Capabilities, ContinueArguments, ExceptionFilterOptions, InitializeRequestArguments,
   7    InitializeRequestArgumentsPathFormat, NextArguments, SetVariableResponse, SourceBreakpoint,
   8    StepInArguments, StepOutArguments, SteppingGranularity, ValueFormat, Variable,
   9    VariablesArgumentsFilter,
  10    client::SessionId,
  11    proto_conversions::ProtoConversion,
  12    requests::{Continue, Next},
  13};
  14
  15use rpc::proto;
  16use serde_json::Value;
  17use util::ResultExt;
  18
  19pub trait LocalDapCommand: 'static + Send + Sync + std::fmt::Debug {
  20    type Response: 'static + Send + std::fmt::Debug;
  21    type DapRequest: 'static + Send + dap::requests::Request;
  22    /// Is this request idempotent? Is it safe to cache the response for as long as the execution environment is unchanged?
  23    const CACHEABLE: bool = false;
  24
  25    fn is_supported(_capabilities: &Capabilities) -> bool {
  26        true
  27    }
  28
  29    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments;
  30
  31    fn response_from_dap(
  32        &self,
  33        message: <Self::DapRequest as dap::requests::Request>::Response,
  34    ) -> Result<Self::Response>;
  35}
  36
  37pub trait DapCommand: LocalDapCommand {
  38    type ProtoRequest: 'static + Send;
  39    type ProtoResponse: 'static + Send;
  40
  41    #[allow(dead_code)]
  42    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId;
  43
  44    #[allow(dead_code)]
  45    fn from_proto(request: &Self::ProtoRequest) -> Self;
  46
  47    #[allow(unused)]
  48    fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest;
  49
  50    #[allow(dead_code)]
  51    fn response_to_proto(
  52        debug_client_id: SessionId,
  53        message: Self::Response,
  54    ) -> Self::ProtoResponse;
  55
  56    #[allow(unused)]
  57    fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response>;
  58}
  59
  60impl<T: LocalDapCommand> LocalDapCommand for Arc<T> {
  61    type Response = T::Response;
  62    type DapRequest = T::DapRequest;
  63
  64    fn is_supported(capabilities: &Capabilities) -> bool {
  65        T::is_supported(capabilities)
  66    }
  67
  68    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
  69        T::to_dap(self)
  70    }
  71
  72    fn response_from_dap(
  73        &self,
  74        message: <Self::DapRequest as dap::requests::Request>::Response,
  75    ) -> Result<Self::Response> {
  76        T::response_from_dap(self, message)
  77    }
  78}
  79
  80impl<T: DapCommand> DapCommand for Arc<T> {
  81    type ProtoRequest = T::ProtoRequest;
  82    type ProtoResponse = T::ProtoResponse;
  83
  84    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
  85        T::client_id_from_proto(request)
  86    }
  87
  88    fn from_proto(request: &Self::ProtoRequest) -> Self {
  89        Arc::new(T::from_proto(request))
  90    }
  91
  92    fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
  93        T::to_proto(self, debug_client_id, upstream_project_id)
  94    }
  95
  96    fn response_to_proto(
  97        debug_client_id: SessionId,
  98        message: Self::Response,
  99    ) -> Self::ProtoResponse {
 100        T::response_to_proto(debug_client_id, message)
 101    }
 102
 103    fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
 104        T::response_from_proto(self, message)
 105    }
 106}
 107
 108#[derive(Debug, Hash, PartialEq, Eq)]
 109pub struct StepCommand {
 110    pub thread_id: i64,
 111    pub granularity: Option<SteppingGranularity>,
 112    pub single_thread: Option<bool>,
 113}
 114
 115impl StepCommand {
 116    fn from_proto(message: proto::DapNextRequest) -> Self {
 117        const LINE: i32 = proto::SteppingGranularity::Line as i32;
 118        const INSTRUCTION: i32 = proto::SteppingGranularity::Instruction as i32;
 119
 120        let granularity = message.granularity.map(|granularity| match granularity {
 121            LINE => SteppingGranularity::Line,
 122            INSTRUCTION => SteppingGranularity::Instruction,
 123            _ => SteppingGranularity::Statement,
 124        });
 125
 126        Self {
 127            thread_id: message.thread_id,
 128            granularity,
 129            single_thread: message.single_thread,
 130        }
 131    }
 132}
 133
 134#[derive(Debug, Hash, PartialEq, Eq)]
 135pub(crate) struct NextCommand {
 136    pub inner: StepCommand,
 137}
 138
 139impl LocalDapCommand for NextCommand {
 140    type Response = <Next as dap::requests::Request>::Response;
 141    type DapRequest = Next;
 142
 143    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
 144        NextArguments {
 145            thread_id: self.inner.thread_id,
 146            single_thread: self.inner.single_thread,
 147            granularity: self.inner.granularity,
 148        }
 149    }
 150    fn response_from_dap(
 151        &self,
 152        _message: <Self::DapRequest as dap::requests::Request>::Response,
 153    ) -> Result<Self::Response> {
 154        Ok(())
 155    }
 156}
 157
 158impl DapCommand for NextCommand {
 159    type ProtoRequest = proto::DapNextRequest;
 160    type ProtoResponse = proto::Ack;
 161
 162    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
 163        SessionId::from_proto(request.client_id)
 164    }
 165
 166    fn from_proto(request: &Self::ProtoRequest) -> Self {
 167        Self {
 168            inner: StepCommand::from_proto(request.clone()),
 169        }
 170    }
 171
 172    fn response_to_proto(
 173        _debug_client_id: SessionId,
 174        _message: Self::Response,
 175    ) -> Self::ProtoResponse {
 176        proto::Ack {}
 177    }
 178
 179    fn to_proto(
 180        &self,
 181        debug_client_id: SessionId,
 182        upstream_project_id: u64,
 183    ) -> proto::DapNextRequest {
 184        proto::DapNextRequest {
 185            project_id: upstream_project_id,
 186            client_id: debug_client_id.to_proto(),
 187            thread_id: self.inner.thread_id,
 188            single_thread: self.inner.single_thread,
 189            granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32),
 190        }
 191    }
 192
 193    fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
 194        Ok(())
 195    }
 196}
 197
 198#[derive(Debug, Hash, PartialEq, Eq)]
 199pub(crate) struct StepInCommand {
 200    pub inner: StepCommand,
 201}
 202
 203impl LocalDapCommand for StepInCommand {
 204    type Response = <dap::requests::StepIn as dap::requests::Request>::Response;
 205    type DapRequest = dap::requests::StepIn;
 206
 207    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
 208        StepInArguments {
 209            thread_id: self.inner.thread_id,
 210            single_thread: self.inner.single_thread,
 211            target_id: None,
 212            granularity: self.inner.granularity,
 213        }
 214    }
 215
 216    fn response_from_dap(
 217        &self,
 218        _message: <Self::DapRequest as dap::requests::Request>::Response,
 219    ) -> Result<Self::Response> {
 220        Ok(())
 221    }
 222}
 223
 224impl DapCommand for StepInCommand {
 225    type ProtoRequest = proto::DapStepInRequest;
 226    type ProtoResponse = proto::Ack;
 227
 228    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
 229        SessionId::from_proto(request.client_id)
 230    }
 231
 232    fn from_proto(request: &Self::ProtoRequest) -> Self {
 233        Self {
 234            inner: StepCommand::from_proto(proto::DapNextRequest {
 235                project_id: request.project_id,
 236                client_id: request.client_id,
 237                thread_id: request.thread_id,
 238                single_thread: request.single_thread,
 239                granularity: request.granularity,
 240            }),
 241        }
 242    }
 243
 244    fn response_to_proto(
 245        _debug_client_id: SessionId,
 246        _message: Self::Response,
 247    ) -> Self::ProtoResponse {
 248        proto::Ack {}
 249    }
 250
 251    fn to_proto(
 252        &self,
 253        debug_client_id: SessionId,
 254        upstream_project_id: u64,
 255    ) -> proto::DapStepInRequest {
 256        proto::DapStepInRequest {
 257            project_id: upstream_project_id,
 258            client_id: debug_client_id.to_proto(),
 259            thread_id: self.inner.thread_id,
 260            single_thread: self.inner.single_thread,
 261            granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32),
 262            target_id: None,
 263        }
 264    }
 265
 266    fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
 267        Ok(())
 268    }
 269}
 270
 271#[derive(Debug, Hash, PartialEq, Eq)]
 272pub(crate) struct StepOutCommand {
 273    pub inner: StepCommand,
 274}
 275
 276impl LocalDapCommand for StepOutCommand {
 277    type Response = <dap::requests::StepOut as dap::requests::Request>::Response;
 278    type DapRequest = dap::requests::StepOut;
 279
 280    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
 281        StepOutArguments {
 282            thread_id: self.inner.thread_id,
 283            single_thread: self.inner.single_thread,
 284            granularity: self.inner.granularity,
 285        }
 286    }
 287
 288    fn response_from_dap(
 289        &self,
 290        _message: <Self::DapRequest as dap::requests::Request>::Response,
 291    ) -> Result<Self::Response> {
 292        Ok(())
 293    }
 294}
 295
 296impl DapCommand for StepOutCommand {
 297    type ProtoRequest = proto::DapStepOutRequest;
 298    type ProtoResponse = proto::Ack;
 299
 300    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
 301        SessionId::from_proto(request.client_id)
 302    }
 303
 304    fn from_proto(request: &Self::ProtoRequest) -> Self {
 305        Self {
 306            inner: StepCommand::from_proto(proto::DapNextRequest {
 307                project_id: request.project_id,
 308                client_id: request.client_id,
 309                thread_id: request.thread_id,
 310                single_thread: request.single_thread,
 311                granularity: request.granularity,
 312            }),
 313        }
 314    }
 315
 316    fn response_to_proto(
 317        _debug_client_id: SessionId,
 318        _message: Self::Response,
 319    ) -> Self::ProtoResponse {
 320        proto::Ack {}
 321    }
 322
 323    fn to_proto(
 324        &self,
 325        debug_client_id: SessionId,
 326        upstream_project_id: u64,
 327    ) -> proto::DapStepOutRequest {
 328        proto::DapStepOutRequest {
 329            project_id: upstream_project_id,
 330            client_id: debug_client_id.to_proto(),
 331            thread_id: self.inner.thread_id,
 332            single_thread: self.inner.single_thread,
 333            granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32),
 334        }
 335    }
 336
 337    fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
 338        Ok(())
 339    }
 340}
 341
 342#[derive(Debug, Hash, PartialEq, Eq)]
 343pub(crate) struct StepBackCommand {
 344    pub inner: StepCommand,
 345}
 346impl LocalDapCommand for StepBackCommand {
 347    type Response = <dap::requests::StepBack as dap::requests::Request>::Response;
 348    type DapRequest = dap::requests::StepBack;
 349
 350    fn is_supported(capabilities: &Capabilities) -> bool {
 351        capabilities.supports_step_back.unwrap_or_default()
 352    }
 353
 354    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
 355        dap::StepBackArguments {
 356            thread_id: self.inner.thread_id,
 357            single_thread: self.inner.single_thread,
 358            granularity: self.inner.granularity,
 359        }
 360    }
 361
 362    fn response_from_dap(
 363        &self,
 364        _message: <Self::DapRequest as dap::requests::Request>::Response,
 365    ) -> Result<Self::Response> {
 366        Ok(())
 367    }
 368}
 369
 370impl DapCommand for StepBackCommand {
 371    type ProtoRequest = proto::DapStepBackRequest;
 372    type ProtoResponse = proto::Ack;
 373
 374    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
 375        SessionId::from_proto(request.client_id)
 376    }
 377
 378    fn from_proto(request: &Self::ProtoRequest) -> Self {
 379        Self {
 380            inner: StepCommand::from_proto(proto::DapNextRequest {
 381                project_id: request.project_id,
 382                client_id: request.client_id,
 383                thread_id: request.thread_id,
 384                single_thread: request.single_thread,
 385                granularity: request.granularity,
 386            }),
 387        }
 388    }
 389
 390    fn response_to_proto(
 391        _debug_client_id: SessionId,
 392        _message: Self::Response,
 393    ) -> Self::ProtoResponse {
 394        proto::Ack {}
 395    }
 396
 397    fn to_proto(
 398        &self,
 399        debug_client_id: SessionId,
 400        upstream_project_id: u64,
 401    ) -> proto::DapStepBackRequest {
 402        proto::DapStepBackRequest {
 403            project_id: upstream_project_id,
 404            client_id: debug_client_id.to_proto(),
 405            thread_id: self.inner.thread_id,
 406            single_thread: self.inner.single_thread,
 407            granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32),
 408        }
 409    }
 410
 411    fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
 412        Ok(())
 413    }
 414}
 415
 416#[derive(Debug, Hash, PartialEq, Eq)]
 417pub(crate) struct ContinueCommand {
 418    pub args: ContinueArguments,
 419}
 420
 421impl LocalDapCommand for ContinueCommand {
 422    type Response = <Continue as dap::requests::Request>::Response;
 423    type DapRequest = Continue;
 424
 425    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
 426        self.args.clone()
 427    }
 428
 429    fn response_from_dap(
 430        &self,
 431        message: <Self::DapRequest as dap::requests::Request>::Response,
 432    ) -> Result<Self::Response> {
 433        Ok(message)
 434    }
 435}
 436
 437impl DapCommand for ContinueCommand {
 438    type ProtoRequest = proto::DapContinueRequest;
 439    type ProtoResponse = proto::DapContinueResponse;
 440
 441    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
 442        SessionId::from_proto(request.client_id)
 443    }
 444
 445    fn to_proto(
 446        &self,
 447        debug_client_id: SessionId,
 448        upstream_project_id: u64,
 449    ) -> proto::DapContinueRequest {
 450        proto::DapContinueRequest {
 451            project_id: upstream_project_id,
 452            client_id: debug_client_id.to_proto(),
 453            thread_id: self.args.thread_id,
 454            single_thread: self.args.single_thread,
 455        }
 456    }
 457
 458    fn from_proto(request: &Self::ProtoRequest) -> Self {
 459        Self {
 460            args: ContinueArguments {
 461                thread_id: request.thread_id,
 462                single_thread: request.single_thread,
 463            },
 464        }
 465    }
 466
 467    fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
 468        Ok(Self::Response {
 469            all_threads_continued: message.all_threads_continued,
 470        })
 471    }
 472
 473    fn response_to_proto(
 474        debug_client_id: SessionId,
 475        message: Self::Response,
 476    ) -> Self::ProtoResponse {
 477        proto::DapContinueResponse {
 478            client_id: debug_client_id.to_proto(),
 479            all_threads_continued: message.all_threads_continued,
 480        }
 481    }
 482}
 483
 484#[derive(Debug, Hash, PartialEq, Eq)]
 485pub(crate) struct PauseCommand {
 486    pub thread_id: i64,
 487}
 488
 489impl LocalDapCommand for PauseCommand {
 490    type Response = <dap::requests::Pause as dap::requests::Request>::Response;
 491    type DapRequest = dap::requests::Pause;
 492    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
 493        dap::PauseArguments {
 494            thread_id: self.thread_id,
 495        }
 496    }
 497
 498    fn response_from_dap(
 499        &self,
 500        _message: <Self::DapRequest as dap::requests::Request>::Response,
 501    ) -> Result<Self::Response> {
 502        Ok(())
 503    }
 504}
 505
 506impl DapCommand for PauseCommand {
 507    type ProtoRequest = proto::DapPauseRequest;
 508    type ProtoResponse = proto::Ack;
 509
 510    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
 511        SessionId::from_proto(request.client_id)
 512    }
 513
 514    fn from_proto(request: &Self::ProtoRequest) -> Self {
 515        Self {
 516            thread_id: request.thread_id,
 517        }
 518    }
 519
 520    fn to_proto(
 521        &self,
 522        debug_client_id: SessionId,
 523        upstream_project_id: u64,
 524    ) -> proto::DapPauseRequest {
 525        proto::DapPauseRequest {
 526            project_id: upstream_project_id,
 527            client_id: debug_client_id.to_proto(),
 528            thread_id: self.thread_id,
 529        }
 530    }
 531
 532    fn response_to_proto(
 533        _debug_client_id: SessionId,
 534        _message: Self::Response,
 535    ) -> Self::ProtoResponse {
 536        proto::Ack {}
 537    }
 538
 539    fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
 540        Ok(())
 541    }
 542}
 543
 544#[derive(Debug, Hash, PartialEq, Eq)]
 545pub(crate) struct DisconnectCommand {
 546    pub restart: Option<bool>,
 547    pub terminate_debuggee: Option<bool>,
 548    pub suspend_debuggee: Option<bool>,
 549}
 550
 551impl LocalDapCommand for DisconnectCommand {
 552    type Response = <dap::requests::Disconnect as dap::requests::Request>::Response;
 553    type DapRequest = dap::requests::Disconnect;
 554
 555    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
 556        dap::DisconnectArguments {
 557            restart: self.restart,
 558            terminate_debuggee: self.terminate_debuggee,
 559            suspend_debuggee: self.suspend_debuggee,
 560        }
 561    }
 562
 563    fn response_from_dap(
 564        &self,
 565        _message: <Self::DapRequest as dap::requests::Request>::Response,
 566    ) -> Result<Self::Response> {
 567        Ok(())
 568    }
 569}
 570
 571impl DapCommand for DisconnectCommand {
 572    type ProtoRequest = proto::DapDisconnectRequest;
 573    type ProtoResponse = proto::Ack;
 574
 575    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
 576        SessionId::from_proto(request.client_id)
 577    }
 578
 579    fn from_proto(request: &Self::ProtoRequest) -> Self {
 580        Self {
 581            restart: request.restart,
 582            terminate_debuggee: request.terminate_debuggee,
 583            suspend_debuggee: request.suspend_debuggee,
 584        }
 585    }
 586
 587    fn to_proto(
 588        &self,
 589        debug_client_id: SessionId,
 590        upstream_project_id: u64,
 591    ) -> proto::DapDisconnectRequest {
 592        proto::DapDisconnectRequest {
 593            project_id: upstream_project_id,
 594            client_id: debug_client_id.to_proto(),
 595            restart: self.restart,
 596            terminate_debuggee: self.terminate_debuggee,
 597            suspend_debuggee: self.suspend_debuggee,
 598        }
 599    }
 600
 601    fn response_to_proto(
 602        _debug_client_id: SessionId,
 603        _message: Self::Response,
 604    ) -> Self::ProtoResponse {
 605        proto::Ack {}
 606    }
 607
 608    fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
 609        Ok(())
 610    }
 611}
 612
 613#[derive(Debug, Hash, PartialEq, Eq)]
 614pub(crate) struct TerminateThreadsCommand {
 615    pub thread_ids: Option<Vec<i64>>,
 616}
 617
 618impl LocalDapCommand for TerminateThreadsCommand {
 619    type Response = <dap::requests::TerminateThreads as dap::requests::Request>::Response;
 620    type DapRequest = dap::requests::TerminateThreads;
 621
 622    fn is_supported(capabilities: &Capabilities) -> bool {
 623        capabilities
 624            .supports_terminate_threads_request
 625            .unwrap_or_default()
 626    }
 627
 628    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
 629        dap::TerminateThreadsArguments {
 630            thread_ids: self.thread_ids.clone(),
 631        }
 632    }
 633
 634    fn response_from_dap(
 635        &self,
 636        _message: <Self::DapRequest as dap::requests::Request>::Response,
 637    ) -> Result<Self::Response> {
 638        Ok(())
 639    }
 640}
 641
 642impl DapCommand for TerminateThreadsCommand {
 643    type ProtoRequest = proto::DapTerminateThreadsRequest;
 644    type ProtoResponse = proto::Ack;
 645
 646    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
 647        SessionId::from_proto(request.client_id)
 648    }
 649
 650    fn from_proto(request: &Self::ProtoRequest) -> Self {
 651        let thread_ids = if request.thread_ids.is_empty() {
 652            None
 653        } else {
 654            Some(request.thread_ids.clone())
 655        };
 656
 657        Self { thread_ids }
 658    }
 659
 660    fn to_proto(
 661        &self,
 662        debug_client_id: SessionId,
 663        upstream_project_id: u64,
 664    ) -> proto::DapTerminateThreadsRequest {
 665        proto::DapTerminateThreadsRequest {
 666            project_id: upstream_project_id,
 667            client_id: debug_client_id.to_proto(),
 668            thread_ids: self.thread_ids.clone().unwrap_or_default(),
 669        }
 670    }
 671
 672    fn response_to_proto(
 673        _debug_client_id: SessionId,
 674        _message: Self::Response,
 675    ) -> Self::ProtoResponse {
 676        proto::Ack {}
 677    }
 678
 679    fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
 680        Ok(())
 681    }
 682}
 683
 684#[derive(Debug, Hash, PartialEq, Eq)]
 685pub(crate) struct TerminateCommand {
 686    pub restart: Option<bool>,
 687}
 688
 689impl LocalDapCommand for TerminateCommand {
 690    type Response = <dap::requests::Terminate as dap::requests::Request>::Response;
 691    type DapRequest = dap::requests::Terminate;
 692
 693    fn is_supported(capabilities: &Capabilities) -> bool {
 694        capabilities.supports_terminate_request.unwrap_or_default()
 695    }
 696    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
 697        dap::TerminateArguments {
 698            restart: self.restart,
 699        }
 700    }
 701
 702    fn response_from_dap(
 703        &self,
 704        _message: <Self::DapRequest as dap::requests::Request>::Response,
 705    ) -> Result<Self::Response> {
 706        Ok(())
 707    }
 708}
 709
 710impl DapCommand for TerminateCommand {
 711    type ProtoRequest = proto::DapTerminateRequest;
 712    type ProtoResponse = proto::Ack;
 713
 714    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
 715        SessionId::from_proto(request.client_id)
 716    }
 717
 718    fn from_proto(request: &Self::ProtoRequest) -> Self {
 719        Self {
 720            restart: request.restart,
 721        }
 722    }
 723
 724    fn to_proto(
 725        &self,
 726        debug_client_id: SessionId,
 727        upstream_project_id: u64,
 728    ) -> proto::DapTerminateRequest {
 729        proto::DapTerminateRequest {
 730            project_id: upstream_project_id,
 731            client_id: debug_client_id.to_proto(),
 732            restart: self.restart,
 733        }
 734    }
 735
 736    fn response_to_proto(
 737        _debug_client_id: SessionId,
 738        _message: Self::Response,
 739    ) -> Self::ProtoResponse {
 740        proto::Ack {}
 741    }
 742
 743    fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
 744        Ok(())
 745    }
 746}
 747
 748#[derive(Debug, Hash, PartialEq, Eq)]
 749pub(crate) struct RestartCommand {
 750    pub raw: serde_json::Value,
 751}
 752
 753impl LocalDapCommand for RestartCommand {
 754    type Response = <dap::requests::Restart as dap::requests::Request>::Response;
 755    type DapRequest = dap::requests::Restart;
 756
 757    fn is_supported(capabilities: &Capabilities) -> bool {
 758        capabilities.supports_restart_request.unwrap_or_default()
 759    }
 760
 761    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
 762        dap::RestartArguments {
 763            raw: self.raw.clone(),
 764        }
 765    }
 766
 767    fn response_from_dap(
 768        &self,
 769        _message: <Self::DapRequest as dap::requests::Request>::Response,
 770    ) -> Result<Self::Response> {
 771        Ok(())
 772    }
 773}
 774
 775impl DapCommand for RestartCommand {
 776    type ProtoRequest = proto::DapRestartRequest;
 777    type ProtoResponse = proto::Ack;
 778
 779    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
 780        SessionId::from_proto(request.client_id)
 781    }
 782
 783    fn from_proto(request: &Self::ProtoRequest) -> Self {
 784        Self {
 785            raw: serde_json::from_slice(&request.raw_args)
 786                .log_err()
 787                .unwrap_or(serde_json::Value::Null),
 788        }
 789    }
 790
 791    fn to_proto(
 792        &self,
 793        debug_client_id: SessionId,
 794        upstream_project_id: u64,
 795    ) -> proto::DapRestartRequest {
 796        let raw_args = serde_json::to_vec(&self.raw).log_err().unwrap_or_default();
 797
 798        proto::DapRestartRequest {
 799            project_id: upstream_project_id,
 800            client_id: debug_client_id.to_proto(),
 801            raw_args,
 802        }
 803    }
 804
 805    fn response_to_proto(
 806        _debug_client_id: SessionId,
 807        _message: Self::Response,
 808    ) -> Self::ProtoResponse {
 809        proto::Ack {}
 810    }
 811
 812    fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
 813        Ok(())
 814    }
 815}
 816
 817#[derive(Clone, Debug, Hash, PartialEq, Eq)]
 818pub struct VariablesCommand {
 819    pub variables_reference: u64,
 820    pub filter: Option<VariablesArgumentsFilter>,
 821    pub start: Option<u64>,
 822    pub count: Option<u64>,
 823    pub format: Option<ValueFormat>,
 824}
 825
 826impl LocalDapCommand for VariablesCommand {
 827    type Response = Vec<Variable>;
 828    type DapRequest = dap::requests::Variables;
 829    const CACHEABLE: bool = true;
 830
 831    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
 832        dap::VariablesArguments {
 833            variables_reference: self.variables_reference,
 834            filter: self.filter,
 835            start: self.start,
 836            count: self.count,
 837            format: self.format.clone(),
 838        }
 839    }
 840
 841    fn response_from_dap(
 842        &self,
 843        message: <Self::DapRequest as dap::requests::Request>::Response,
 844    ) -> Result<Self::Response> {
 845        Ok(message.variables)
 846    }
 847}
 848
 849impl DapCommand for VariablesCommand {
 850    type ProtoRequest = proto::VariablesRequest;
 851    type ProtoResponse = proto::DapVariables;
 852
 853    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
 854        SessionId::from_proto(request.client_id)
 855    }
 856
 857    fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
 858        proto::VariablesRequest {
 859            project_id: upstream_project_id,
 860            client_id: debug_client_id.to_proto(),
 861            variables_reference: self.variables_reference,
 862            filter: None,
 863            start: self.start,
 864            count: self.count,
 865            format: None,
 866        }
 867    }
 868
 869    fn from_proto(request: &Self::ProtoRequest) -> Self {
 870        Self {
 871            variables_reference: request.variables_reference,
 872            filter: None,
 873            start: request.start,
 874            count: request.count,
 875            format: None,
 876        }
 877    }
 878
 879    fn response_to_proto(
 880        debug_client_id: SessionId,
 881        message: Self::Response,
 882    ) -> Self::ProtoResponse {
 883        proto::DapVariables {
 884            client_id: debug_client_id.to_proto(),
 885            variables: message.to_proto(),
 886        }
 887    }
 888
 889    fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
 890        Ok(Vec::from_proto(message.variables))
 891    }
 892}
 893
 894#[derive(Debug, Hash, PartialEq, Eq)]
 895pub(crate) struct SetVariableValueCommand {
 896    pub name: String,
 897    pub value: String,
 898    pub variables_reference: u64,
 899}
 900impl LocalDapCommand for SetVariableValueCommand {
 901    type Response = SetVariableResponse;
 902    type DapRequest = dap::requests::SetVariable;
 903    fn is_supported(capabilities: &Capabilities) -> bool {
 904        capabilities.supports_set_variable.unwrap_or_default()
 905    }
 906    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
 907        dap::SetVariableArguments {
 908            format: None,
 909            name: self.name.clone(),
 910            value: self.value.clone(),
 911            variables_reference: self.variables_reference,
 912        }
 913    }
 914    fn response_from_dap(
 915        &self,
 916        message: <Self::DapRequest as dap::requests::Request>::Response,
 917    ) -> Result<Self::Response> {
 918        Ok(message)
 919    }
 920}
 921
 922impl DapCommand for SetVariableValueCommand {
 923    type ProtoRequest = proto::DapSetVariableValueRequest;
 924    type ProtoResponse = proto::DapSetVariableValueResponse;
 925
 926    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
 927        SessionId::from_proto(request.client_id)
 928    }
 929
 930    fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
 931        proto::DapSetVariableValueRequest {
 932            project_id: upstream_project_id,
 933            client_id: debug_client_id.to_proto(),
 934            variables_reference: self.variables_reference,
 935            value: self.value.clone(),
 936            name: self.name.clone(),
 937        }
 938    }
 939
 940    fn from_proto(request: &Self::ProtoRequest) -> Self {
 941        Self {
 942            variables_reference: request.variables_reference,
 943            name: request.name.clone(),
 944            value: request.value.clone(),
 945        }
 946    }
 947
 948    fn response_to_proto(
 949        debug_client_id: SessionId,
 950        message: Self::Response,
 951    ) -> Self::ProtoResponse {
 952        proto::DapSetVariableValueResponse {
 953            client_id: debug_client_id.to_proto(),
 954            value: message.value,
 955            variable_type: message.type_,
 956            named_variables: message.named_variables,
 957            variables_reference: message.variables_reference,
 958            indexed_variables: message.indexed_variables,
 959            memory_reference: message.memory_reference,
 960        }
 961    }
 962
 963    fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
 964        Ok(SetVariableResponse {
 965            value: message.value,
 966            type_: message.variable_type,
 967            variables_reference: message.variables_reference,
 968            named_variables: message.named_variables,
 969            indexed_variables: message.indexed_variables,
 970            memory_reference: message.memory_reference,
 971            value_location_reference: None, // TODO
 972        })
 973    }
 974}
 975
 976#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 977pub(crate) struct RestartStackFrameCommand {
 978    pub stack_frame_id: u64,
 979}
 980
 981impl LocalDapCommand for RestartStackFrameCommand {
 982    type Response = <dap::requests::RestartFrame as dap::requests::Request>::Response;
 983    type DapRequest = dap::requests::RestartFrame;
 984
 985    fn is_supported(capabilities: &Capabilities) -> bool {
 986        capabilities.supports_restart_frame.unwrap_or_default()
 987    }
 988
 989    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
 990        dap::RestartFrameArguments {
 991            frame_id: self.stack_frame_id,
 992        }
 993    }
 994
 995    fn response_from_dap(
 996        &self,
 997        _message: <Self::DapRequest as dap::requests::Request>::Response,
 998    ) -> Result<Self::Response> {
 999        Ok(())
1000    }
1001}
1002
1003impl DapCommand for RestartStackFrameCommand {
1004    type ProtoRequest = proto::DapRestartStackFrameRequest;
1005    type ProtoResponse = proto::Ack;
1006
1007    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1008        SessionId::from_proto(request.client_id)
1009    }
1010
1011    fn from_proto(request: &Self::ProtoRequest) -> Self {
1012        Self {
1013            stack_frame_id: request.stack_frame_id,
1014        }
1015    }
1016
1017    fn to_proto(
1018        &self,
1019        debug_client_id: SessionId,
1020        upstream_project_id: u64,
1021    ) -> proto::DapRestartStackFrameRequest {
1022        proto::DapRestartStackFrameRequest {
1023            project_id: upstream_project_id,
1024            client_id: debug_client_id.to_proto(),
1025            stack_frame_id: self.stack_frame_id,
1026        }
1027    }
1028
1029    fn response_to_proto(
1030        _debug_client_id: SessionId,
1031        _message: Self::Response,
1032    ) -> Self::ProtoResponse {
1033        proto::Ack {}
1034    }
1035
1036    fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result<Self::Response> {
1037        Ok(())
1038    }
1039}
1040
1041#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1042pub(crate) struct ModulesCommand;
1043
1044impl LocalDapCommand for ModulesCommand {
1045    type Response = Vec<dap::Module>;
1046    type DapRequest = dap::requests::Modules;
1047    const CACHEABLE: bool = true;
1048
1049    fn is_supported(capabilities: &Capabilities) -> bool {
1050        capabilities.supports_modules_request.unwrap_or_default()
1051    }
1052
1053    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1054        dap::ModulesArguments {
1055            start_module: None,
1056            module_count: None,
1057        }
1058    }
1059
1060    fn response_from_dap(
1061        &self,
1062        message: <Self::DapRequest as dap::requests::Request>::Response,
1063    ) -> Result<Self::Response> {
1064        Ok(message.modules)
1065    }
1066}
1067
1068impl DapCommand for ModulesCommand {
1069    type ProtoRequest = proto::DapModulesRequest;
1070    type ProtoResponse = proto::DapModulesResponse;
1071
1072    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1073        SessionId::from_proto(request.client_id)
1074    }
1075
1076    fn from_proto(_request: &Self::ProtoRequest) -> Self {
1077        Self {}
1078    }
1079
1080    fn to_proto(
1081        &self,
1082        debug_client_id: SessionId,
1083        upstream_project_id: u64,
1084    ) -> proto::DapModulesRequest {
1085        proto::DapModulesRequest {
1086            project_id: upstream_project_id,
1087            client_id: debug_client_id.to_proto(),
1088        }
1089    }
1090
1091    fn response_to_proto(
1092        debug_client_id: SessionId,
1093        message: Self::Response,
1094    ) -> Self::ProtoResponse {
1095        proto::DapModulesResponse {
1096            modules: message
1097                .into_iter()
1098                .map(|module| module.to_proto())
1099                .collect(),
1100            client_id: debug_client_id.to_proto(),
1101        }
1102    }
1103
1104    fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1105        Ok(message
1106            .modules
1107            .into_iter()
1108            .filter_map(|module| dap::Module::from_proto(module).ok())
1109            .collect())
1110    }
1111}
1112
1113#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1114pub(crate) struct LoadedSourcesCommand;
1115
1116impl LocalDapCommand for LoadedSourcesCommand {
1117    type Response = Vec<dap::Source>;
1118    type DapRequest = dap::requests::LoadedSources;
1119    const CACHEABLE: bool = true;
1120
1121    fn is_supported(capabilities: &Capabilities) -> bool {
1122        capabilities
1123            .supports_loaded_sources_request
1124            .unwrap_or_default()
1125    }
1126    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1127        dap::LoadedSourcesArguments {}
1128    }
1129
1130    fn response_from_dap(
1131        &self,
1132        message: <Self::DapRequest as dap::requests::Request>::Response,
1133    ) -> Result<Self::Response> {
1134        Ok(message.sources)
1135    }
1136}
1137
1138impl DapCommand for LoadedSourcesCommand {
1139    type ProtoRequest = proto::DapLoadedSourcesRequest;
1140    type ProtoResponse = proto::DapLoadedSourcesResponse;
1141
1142    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1143        SessionId::from_proto(request.client_id)
1144    }
1145
1146    fn from_proto(_request: &Self::ProtoRequest) -> Self {
1147        Self {}
1148    }
1149
1150    fn to_proto(
1151        &self,
1152        debug_client_id: SessionId,
1153        upstream_project_id: u64,
1154    ) -> proto::DapLoadedSourcesRequest {
1155        proto::DapLoadedSourcesRequest {
1156            project_id: upstream_project_id,
1157            client_id: debug_client_id.to_proto(),
1158        }
1159    }
1160
1161    fn response_to_proto(
1162        debug_client_id: SessionId,
1163        message: Self::Response,
1164    ) -> Self::ProtoResponse {
1165        proto::DapLoadedSourcesResponse {
1166            sources: message
1167                .into_iter()
1168                .map(|source| source.to_proto())
1169                .collect(),
1170            client_id: debug_client_id.to_proto(),
1171        }
1172    }
1173
1174    fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1175        Ok(message
1176            .sources
1177            .into_iter()
1178            .map(dap::Source::from_proto)
1179            .collect())
1180    }
1181}
1182
1183#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1184pub(crate) struct StackTraceCommand {
1185    pub thread_id: i64,
1186    pub start_frame: Option<u64>,
1187    pub levels: Option<u64>,
1188}
1189
1190impl LocalDapCommand for StackTraceCommand {
1191    type Response = Vec<dap::StackFrame>;
1192    type DapRequest = dap::requests::StackTrace;
1193    const CACHEABLE: bool = true;
1194
1195    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1196        dap::StackTraceArguments {
1197            thread_id: self.thread_id,
1198            start_frame: self.start_frame,
1199            levels: self.levels,
1200            format: None,
1201        }
1202    }
1203
1204    fn response_from_dap(
1205        &self,
1206        message: <Self::DapRequest as dap::requests::Request>::Response,
1207    ) -> Result<Self::Response> {
1208        Ok(message.stack_frames)
1209    }
1210}
1211
1212impl DapCommand for StackTraceCommand {
1213    type ProtoRequest = proto::DapStackTraceRequest;
1214    type ProtoResponse = proto::DapStackTraceResponse;
1215
1216    fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
1217        proto::DapStackTraceRequest {
1218            project_id: upstream_project_id,
1219            client_id: debug_client_id.to_proto(),
1220            thread_id: self.thread_id,
1221            start_frame: self.start_frame,
1222            stack_trace_levels: self.levels,
1223        }
1224    }
1225
1226    fn from_proto(request: &Self::ProtoRequest) -> Self {
1227        Self {
1228            thread_id: request.thread_id,
1229            start_frame: request.start_frame,
1230            levels: request.stack_trace_levels,
1231        }
1232    }
1233
1234    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1235        SessionId::from_proto(request.client_id)
1236    }
1237
1238    fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1239        Ok(message
1240            .frames
1241            .into_iter()
1242            .map(dap::StackFrame::from_proto)
1243            .collect())
1244    }
1245
1246    fn response_to_proto(
1247        _debug_client_id: SessionId,
1248        message: Self::Response,
1249    ) -> Self::ProtoResponse {
1250        proto::DapStackTraceResponse {
1251            frames: message.to_proto(),
1252        }
1253    }
1254}
1255
1256#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1257pub(crate) struct ScopesCommand {
1258    pub stack_frame_id: u64,
1259}
1260
1261impl LocalDapCommand for ScopesCommand {
1262    type Response = Vec<dap::Scope>;
1263    type DapRequest = dap::requests::Scopes;
1264    const CACHEABLE: bool = true;
1265
1266    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1267        dap::ScopesArguments {
1268            frame_id: self.stack_frame_id,
1269        }
1270    }
1271
1272    fn response_from_dap(
1273        &self,
1274        message: <Self::DapRequest as dap::requests::Request>::Response,
1275    ) -> Result<Self::Response> {
1276        Ok(message.scopes)
1277    }
1278}
1279
1280impl DapCommand for ScopesCommand {
1281    type ProtoRequest = proto::DapScopesRequest;
1282    type ProtoResponse = proto::DapScopesResponse;
1283
1284    fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
1285        proto::DapScopesRequest {
1286            project_id: upstream_project_id,
1287            client_id: debug_client_id.to_proto(),
1288            stack_frame_id: self.stack_frame_id,
1289        }
1290    }
1291
1292    fn from_proto(request: &Self::ProtoRequest) -> Self {
1293        Self {
1294            stack_frame_id: request.stack_frame_id,
1295        }
1296    }
1297
1298    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1299        SessionId::from_proto(request.client_id)
1300    }
1301
1302    fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1303        Ok(Vec::from_proto(message.scopes))
1304    }
1305
1306    fn response_to_proto(
1307        _debug_client_id: SessionId,
1308        message: Self::Response,
1309    ) -> Self::ProtoResponse {
1310        proto::DapScopesResponse {
1311            scopes: message.to_proto(),
1312        }
1313    }
1314}
1315
1316impl LocalDapCommand for super::session::CompletionsQuery {
1317    type Response = dap::CompletionsResponse;
1318    type DapRequest = dap::requests::Completions;
1319    const CACHEABLE: bool = true;
1320
1321    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1322        dap::CompletionsArguments {
1323            text: self.query.clone(),
1324            frame_id: self.frame_id,
1325            column: self.column,
1326            line: None,
1327        }
1328    }
1329
1330    fn response_from_dap(
1331        &self,
1332        message: <Self::DapRequest as dap::requests::Request>::Response,
1333    ) -> Result<Self::Response> {
1334        Ok(message)
1335    }
1336
1337    fn is_supported(capabilities: &Capabilities) -> bool {
1338        capabilities
1339            .supports_completions_request
1340            .unwrap_or_default()
1341    }
1342}
1343
1344impl DapCommand for super::session::CompletionsQuery {
1345    type ProtoRequest = proto::DapCompletionRequest;
1346    type ProtoResponse = proto::DapCompletionResponse;
1347
1348    fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
1349        proto::DapCompletionRequest {
1350            client_id: debug_client_id.to_proto(),
1351            project_id: upstream_project_id,
1352            frame_id: self.frame_id,
1353            query: self.query.clone(),
1354            column: self.column,
1355            line: self.line,
1356        }
1357    }
1358
1359    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1360        SessionId::from_proto(request.client_id)
1361    }
1362
1363    fn from_proto(request: &Self::ProtoRequest) -> Self {
1364        Self {
1365            query: request.query.clone(),
1366            frame_id: request.frame_id,
1367            column: request.column,
1368            line: request.line,
1369        }
1370    }
1371
1372    fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1373        Ok(dap::CompletionsResponse {
1374            targets: Vec::from_proto(message.completions),
1375        })
1376    }
1377
1378    fn response_to_proto(
1379        _debug_client_id: SessionId,
1380        message: Self::Response,
1381    ) -> Self::ProtoResponse {
1382        proto::DapCompletionResponse {
1383            client_id: _debug_client_id.to_proto(),
1384            completions: message.targets.to_proto(),
1385        }
1386    }
1387}
1388
1389#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1390pub(crate) struct EvaluateCommand {
1391    pub expression: String,
1392    pub frame_id: Option<u64>,
1393    pub context: Option<dap::EvaluateArgumentsContext>,
1394    pub source: Option<dap::Source>,
1395}
1396
1397impl LocalDapCommand for EvaluateCommand {
1398    type Response = dap::EvaluateResponse;
1399    type DapRequest = dap::requests::Evaluate;
1400    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1401        dap::EvaluateArguments {
1402            expression: self.expression.clone(),
1403            frame_id: self.frame_id,
1404            context: self.context.clone(),
1405            source: self.source.clone(),
1406            line: None,
1407            column: None,
1408            format: None,
1409        }
1410    }
1411
1412    fn response_from_dap(
1413        &self,
1414        message: <Self::DapRequest as dap::requests::Request>::Response,
1415    ) -> Result<Self::Response> {
1416        Ok(message)
1417    }
1418}
1419impl DapCommand for EvaluateCommand {
1420    type ProtoRequest = proto::DapEvaluateRequest;
1421    type ProtoResponse = proto::DapEvaluateResponse;
1422
1423    fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
1424        proto::DapEvaluateRequest {
1425            client_id: debug_client_id.to_proto(),
1426            project_id: upstream_project_id,
1427            expression: self.expression.clone(),
1428            frame_id: self.frame_id,
1429            context: self
1430                .context
1431                .clone()
1432                .map(|context| context.to_proto().into()),
1433        }
1434    }
1435
1436    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1437        SessionId::from_proto(request.client_id)
1438    }
1439
1440    fn from_proto(request: &Self::ProtoRequest) -> Self {
1441        Self {
1442            expression: request.expression.clone(),
1443            frame_id: request.frame_id,
1444            context: Some(dap::EvaluateArgumentsContext::from_proto(request.context())),
1445            source: None,
1446        }
1447    }
1448
1449    fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1450        Ok(dap::EvaluateResponse {
1451            result: message.result.clone(),
1452            type_: message.evaluate_type.clone(),
1453            presentation_hint: None,
1454            variables_reference: message.variable_reference,
1455            named_variables: message.named_variables,
1456            indexed_variables: message.indexed_variables,
1457            memory_reference: message.memory_reference,
1458            value_location_reference: None, //TODO
1459        })
1460    }
1461
1462    fn response_to_proto(
1463        _debug_client_id: SessionId,
1464        message: Self::Response,
1465    ) -> Self::ProtoResponse {
1466        proto::DapEvaluateResponse {
1467            result: message.result,
1468            evaluate_type: message.type_,
1469            variable_reference: message.variables_reference,
1470            named_variables: message.named_variables,
1471            indexed_variables: message.indexed_variables,
1472            memory_reference: message.memory_reference,
1473        }
1474    }
1475}
1476
1477#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1478pub(crate) struct ThreadsCommand;
1479
1480impl LocalDapCommand for ThreadsCommand {
1481    type Response = Vec<dap::Thread>;
1482    type DapRequest = dap::requests::Threads;
1483    const CACHEABLE: bool = true;
1484
1485    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1486        dap::ThreadsArgument {}
1487    }
1488
1489    fn response_from_dap(
1490        &self,
1491        message: <Self::DapRequest as dap::requests::Request>::Response,
1492    ) -> Result<Self::Response> {
1493        Ok(message.threads)
1494    }
1495}
1496
1497impl DapCommand for ThreadsCommand {
1498    type ProtoRequest = proto::DapThreadsRequest;
1499    type ProtoResponse = proto::DapThreadsResponse;
1500
1501    fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest {
1502        proto::DapThreadsRequest {
1503            project_id: upstream_project_id,
1504            client_id: debug_client_id.to_proto(),
1505        }
1506    }
1507
1508    fn from_proto(_request: &Self::ProtoRequest) -> Self {
1509        Self {}
1510    }
1511
1512    fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId {
1513        SessionId::from_proto(request.client_id)
1514    }
1515
1516    fn response_from_proto(&self, message: Self::ProtoResponse) -> Result<Self::Response> {
1517        Ok(Vec::from_proto(message.threads))
1518    }
1519
1520    fn response_to_proto(
1521        _debug_client_id: SessionId,
1522        message: Self::Response,
1523    ) -> Self::ProtoResponse {
1524        proto::DapThreadsResponse {
1525            threads: message.to_proto(),
1526        }
1527    }
1528}
1529
1530#[derive(Clone, Debug, Hash, PartialEq)]
1531pub(super) struct Initialize {
1532    pub(super) adapter_id: String,
1533}
1534
1535fn dap_client_capabilities(adapter_id: String) -> InitializeRequestArguments {
1536    InitializeRequestArguments {
1537        client_id: Some("zed".to_owned()),
1538        client_name: Some("Zed".to_owned()),
1539        adapter_id,
1540        locale: Some("en-US".to_owned()),
1541        path_format: Some(InitializeRequestArgumentsPathFormat::Path),
1542        supports_variable_type: Some(true),
1543        supports_variable_paging: Some(false),
1544        supports_run_in_terminal_request: Some(true),
1545        supports_memory_references: Some(true),
1546        supports_progress_reporting: Some(false),
1547        supports_invalidated_event: Some(false),
1548        lines_start_at1: Some(true),
1549        columns_start_at1: Some(true),
1550        supports_memory_event: Some(false),
1551        supports_args_can_be_interpreted_by_shell: Some(false),
1552        supports_start_debugging_request: Some(true),
1553        supports_ansistyling: Some(true),
1554    }
1555}
1556
1557impl LocalDapCommand for Initialize {
1558    type Response = Capabilities;
1559    type DapRequest = dap::requests::Initialize;
1560
1561    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1562        dap_client_capabilities(self.adapter_id.clone())
1563    }
1564
1565    fn response_from_dap(
1566        &self,
1567        message: <Self::DapRequest as dap::requests::Request>::Response,
1568    ) -> Result<Self::Response> {
1569        Ok(message)
1570    }
1571}
1572
1573#[derive(Clone, Debug, Hash, PartialEq)]
1574pub(super) struct ConfigurationDone {}
1575
1576impl LocalDapCommand for ConfigurationDone {
1577    type Response = ();
1578    type DapRequest = dap::requests::ConfigurationDone;
1579
1580    fn is_supported(capabilities: &Capabilities) -> bool {
1581        capabilities
1582            .supports_configuration_done_request
1583            .unwrap_or_default()
1584    }
1585
1586    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1587        dap::ConfigurationDoneArguments {}
1588    }
1589
1590    fn response_from_dap(
1591        &self,
1592        message: <Self::DapRequest as dap::requests::Request>::Response,
1593    ) -> Result<Self::Response> {
1594        Ok(message)
1595    }
1596}
1597
1598#[derive(Clone, Debug, Hash, PartialEq)]
1599pub(super) struct Launch {
1600    pub(super) raw: Value,
1601}
1602
1603impl LocalDapCommand for Launch {
1604    type Response = ();
1605    type DapRequest = dap::requests::Launch;
1606
1607    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1608        dap::LaunchRequestArguments {
1609            raw: self.raw.clone(),
1610        }
1611    }
1612
1613    fn response_from_dap(
1614        &self,
1615        message: <Self::DapRequest as dap::requests::Request>::Response,
1616    ) -> Result<Self::Response> {
1617        Ok(message)
1618    }
1619}
1620
1621#[derive(Clone, Debug, Hash, PartialEq)]
1622pub(super) struct Attach {
1623    pub(super) raw: Value,
1624}
1625
1626impl LocalDapCommand for Attach {
1627    type Response = ();
1628    type DapRequest = dap::requests::Attach;
1629
1630    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1631        dap::AttachRequestArguments {
1632            raw: self.raw.clone(),
1633        }
1634    }
1635
1636    fn response_from_dap(
1637        &self,
1638        message: <Self::DapRequest as dap::requests::Request>::Response,
1639    ) -> Result<Self::Response> {
1640        Ok(message)
1641    }
1642}
1643
1644#[derive(Clone, Debug, Hash, PartialEq)]
1645pub(super) struct SetBreakpoints {
1646    pub(super) source: dap::Source,
1647    pub(super) breakpoints: Vec<SourceBreakpoint>,
1648    pub(super) source_modified: Option<bool>,
1649}
1650
1651impl LocalDapCommand for SetBreakpoints {
1652    type Response = Vec<dap::Breakpoint>;
1653    type DapRequest = dap::requests::SetBreakpoints;
1654
1655    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1656        dap::SetBreakpointsArguments {
1657            lines: None,
1658            source_modified: self.source_modified,
1659            source: self.source.clone(),
1660            breakpoints: Some(self.breakpoints.clone()),
1661        }
1662    }
1663
1664    fn response_from_dap(
1665        &self,
1666        message: <Self::DapRequest as dap::requests::Request>::Response,
1667    ) -> Result<Self::Response> {
1668        Ok(message.breakpoints)
1669    }
1670}
1671
1672#[derive(Clone, Debug, Hash, PartialEq, Eq)]
1673pub enum DataBreakpointContext {
1674    Variable {
1675        variables_reference: u64,
1676        name: String,
1677        bytes: Option<u64>,
1678    },
1679    Expression {
1680        expression: String,
1681        frame_id: Option<u64>,
1682    },
1683    Address {
1684        address: String,
1685        bytes: Option<u64>,
1686    },
1687}
1688
1689impl DataBreakpointContext {
1690    pub fn human_readable_label(&self) -> String {
1691        match self {
1692            DataBreakpointContext::Variable { name, .. } => format!("Variable: {}", name),
1693            DataBreakpointContext::Expression { expression, .. } => {
1694                format!("Expression: {}", expression)
1695            }
1696            DataBreakpointContext::Address { address, bytes } => {
1697                let mut label = format!("Address: {}", address);
1698                if let Some(bytes) = bytes {
1699                    label.push_str(&format!(
1700                        " ({} byte{})",
1701                        bytes,
1702                        if *bytes == 1 { "" } else { "s" }
1703                    ));
1704                }
1705                label
1706            }
1707        }
1708    }
1709}
1710
1711#[derive(Clone, Debug, Hash, PartialEq, Eq)]
1712pub(crate) struct DataBreakpointInfoCommand {
1713    pub context: Arc<DataBreakpointContext>,
1714    pub mode: Option<String>,
1715}
1716
1717impl LocalDapCommand for DataBreakpointInfoCommand {
1718    type Response = dap::DataBreakpointInfoResponse;
1719    type DapRequest = dap::requests::DataBreakpointInfo;
1720    const CACHEABLE: bool = true;
1721
1722    // todo(debugger): We should expand this trait in the future to take a &self
1723    // Depending on this command is_supported could be differentb
1724    fn is_supported(capabilities: &Capabilities) -> bool {
1725        capabilities.supports_data_breakpoints.unwrap_or(false)
1726    }
1727
1728    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1729        let (variables_reference, name, frame_id, as_address, bytes) = match &*self.context {
1730            DataBreakpointContext::Variable {
1731                variables_reference,
1732                name,
1733                bytes,
1734            } => (
1735                Some(*variables_reference),
1736                name.clone(),
1737                None,
1738                Some(false),
1739                *bytes,
1740            ),
1741            DataBreakpointContext::Expression {
1742                expression,
1743                frame_id,
1744            } => (None, expression.clone(), *frame_id, Some(false), None),
1745            DataBreakpointContext::Address { address, bytes } => {
1746                (None, address.clone(), None, Some(true), *bytes)
1747            }
1748        };
1749
1750        dap::DataBreakpointInfoArguments {
1751            variables_reference,
1752            name,
1753            frame_id,
1754            bytes,
1755            as_address,
1756            mode: self.mode.clone(),
1757        }
1758    }
1759
1760    fn response_from_dap(
1761        &self,
1762        message: <Self::DapRequest as dap::requests::Request>::Response,
1763    ) -> Result<Self::Response> {
1764        Ok(message)
1765    }
1766}
1767
1768#[derive(Clone, Debug, Hash, PartialEq, Eq)]
1769pub(crate) struct SetDataBreakpointsCommand {
1770    pub breakpoints: Vec<dap::DataBreakpoint>,
1771}
1772
1773impl LocalDapCommand for SetDataBreakpointsCommand {
1774    type Response = Vec<dap::Breakpoint>;
1775    type DapRequest = dap::requests::SetDataBreakpoints;
1776
1777    fn is_supported(capabilities: &Capabilities) -> bool {
1778        capabilities.supports_data_breakpoints.unwrap_or(false)
1779    }
1780
1781    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1782        dap::SetDataBreakpointsArguments {
1783            breakpoints: self.breakpoints.clone(),
1784        }
1785    }
1786
1787    fn response_from_dap(
1788        &self,
1789        message: <Self::DapRequest as dap::requests::Request>::Response,
1790    ) -> Result<Self::Response> {
1791        Ok(message.breakpoints)
1792    }
1793}
1794
1795#[derive(Clone, Debug, Hash, PartialEq)]
1796pub(super) enum SetExceptionBreakpoints {
1797    Plain {
1798        filters: Vec<String>,
1799    },
1800    WithOptions {
1801        filters: Vec<ExceptionFilterOptions>,
1802    },
1803}
1804
1805impl LocalDapCommand for SetExceptionBreakpoints {
1806    type Response = Vec<dap::Breakpoint>;
1807    type DapRequest = dap::requests::SetExceptionBreakpoints;
1808
1809    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1810        match self {
1811            SetExceptionBreakpoints::Plain { filters } => dap::SetExceptionBreakpointsArguments {
1812                filters: filters.clone(),
1813                exception_options: None,
1814                filter_options: None,
1815            },
1816            SetExceptionBreakpoints::WithOptions { filters } => {
1817                dap::SetExceptionBreakpointsArguments {
1818                    filters: vec![],
1819                    filter_options: Some(filters.clone()),
1820                    exception_options: None,
1821                }
1822            }
1823        }
1824    }
1825
1826    fn response_from_dap(
1827        &self,
1828        message: <Self::DapRequest as dap::requests::Request>::Response,
1829    ) -> Result<Self::Response> {
1830        Ok(message.breakpoints.unwrap_or_default())
1831    }
1832}
1833
1834#[derive(Clone, Debug, Hash, PartialEq, Eq)]
1835pub(super) struct LocationsCommand {
1836    pub(super) reference: u64,
1837}
1838
1839impl LocalDapCommand for LocationsCommand {
1840    type Response = dap::LocationsResponse;
1841    type DapRequest = dap::requests::Locations;
1842    const CACHEABLE: bool = true;
1843
1844    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1845        dap::LocationsArguments {
1846            location_reference: self.reference,
1847        }
1848    }
1849
1850    fn response_from_dap(
1851        &self,
1852        message: <Self::DapRequest as dap::requests::Request>::Response,
1853    ) -> Result<Self::Response> {
1854        Ok(message)
1855    }
1856}
1857
1858impl DapCommand for LocationsCommand {
1859    type ProtoRequest = proto::DapLocationsRequest;
1860    type ProtoResponse = proto::DapLocationsResponse;
1861
1862    fn client_id_from_proto(message: &Self::ProtoRequest) -> SessionId {
1863        SessionId::from_proto(message.session_id)
1864    }
1865
1866    fn from_proto(message: &Self::ProtoRequest) -> Self {
1867        Self {
1868            reference: message.location_reference,
1869        }
1870    }
1871
1872    fn to_proto(&self, session_id: SessionId, project_id: u64) -> Self::ProtoRequest {
1873        proto::DapLocationsRequest {
1874            project_id,
1875            session_id: session_id.to_proto(),
1876            location_reference: self.reference,
1877        }
1878    }
1879
1880    fn response_to_proto(_: SessionId, response: Self::Response) -> Self::ProtoResponse {
1881        proto::DapLocationsResponse {
1882            source: Some(response.source.to_proto()),
1883            line: response.line,
1884            column: response.column,
1885            end_line: response.end_line,
1886            end_column: response.end_column,
1887        }
1888    }
1889
1890    fn response_from_proto(&self, response: Self::ProtoResponse) -> Result<Self::Response> {
1891        Ok(dap::LocationsResponse {
1892            source: response
1893                .source
1894                .map(<dap::Source as ProtoConversion>::from_proto)
1895                .context("Missing `source` field in Locations proto")?,
1896            line: response.line,
1897            column: response.column,
1898            end_line: response.end_line,
1899            end_column: response.end_column,
1900        })
1901    }
1902}
1903
1904#[derive(Clone, Debug, Hash, PartialEq, Eq)]
1905pub(crate) struct ReadMemory {
1906    pub(crate) memory_reference: String,
1907    pub(crate) offset: Option<u64>,
1908    pub(crate) count: u64,
1909}
1910
1911#[derive(Clone, Debug, PartialEq)]
1912pub(crate) struct ReadMemoryResponse {
1913    pub(super) address: Arc<str>,
1914    pub(super) unreadable_bytes: Option<u64>,
1915    pub(super) content: Arc<[u8]>,
1916}
1917
1918impl LocalDapCommand for ReadMemory {
1919    type Response = ReadMemoryResponse;
1920    type DapRequest = dap::requests::ReadMemory;
1921    const CACHEABLE: bool = true;
1922
1923    fn is_supported(capabilities: &Capabilities) -> bool {
1924        capabilities
1925            .supports_read_memory_request
1926            .unwrap_or_default()
1927    }
1928    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1929        dap::ReadMemoryArguments {
1930            memory_reference: self.memory_reference.clone(),
1931            offset: self.offset,
1932            count: self.count,
1933        }
1934    }
1935
1936    fn response_from_dap(
1937        &self,
1938        message: <Self::DapRequest as dap::requests::Request>::Response,
1939    ) -> Result<Self::Response> {
1940        let data = if let Some(data) = message.data {
1941            base64::engine::general_purpose::STANDARD
1942                .decode(data)
1943                .log_err()
1944                .context("parsing base64 data from DAP's ReadMemory response")?
1945        } else {
1946            vec![]
1947        };
1948
1949        Ok(ReadMemoryResponse {
1950            address: message.address.into(),
1951            content: data.into(),
1952            unreadable_bytes: message.unreadable_bytes,
1953        })
1954    }
1955}
1956
1957impl LocalDapCommand for dap::WriteMemoryArguments {
1958    type Response = dap::WriteMemoryResponse;
1959    type DapRequest = dap::requests::WriteMemory;
1960    fn is_supported(capabilities: &Capabilities) -> bool {
1961        capabilities
1962            .supports_write_memory_request
1963            .unwrap_or_default()
1964    }
1965    fn to_dap(&self) -> <Self::DapRequest as dap::requests::Request>::Arguments {
1966        self.clone()
1967    }
1968
1969    fn response_from_dap(
1970        &self,
1971        message: <Self::DapRequest as dap::requests::Request>::Response,
1972    ) -> Result<Self::Response> {
1973        Ok(message)
1974    }
1975}