RustでクレートのStructを自作の複数のインスタンスで共有して使用したい。 cannot move out of dereference of ~~~

前提

現在、Rust + ESP32でI2Cに接続したPWMボードと9軸センサーを制御するプログラムを作成している。

同じI2Cバスに2つの制御対象を接続するため、I2Cインスタンスは共有したいと考えたため、

I2Cはesp_idf_halクレートを使用してインスタンスを生成し、
そのインスタンスを保持する自作のI2CDriverクラスを作成し、
PWMコントローラークラスと9軸コントローラークラスでそのI2CDriverクラスのインスタンスを共有して保持するように作成していた。

今回の問題が発生した経緯

次にPCA9685チップが搭載されているPWMボードの制御をおこないたいと思い、
PWM-Pca9685クレートを使用し、
PWMコントローラークラス内で保持しているI2Cインスタンスを使用してPca9685構造体をnew関数でインスタンス化しようとした。

しかし、new関数の引数にI2Cインスタンスを渡そうとすると、

cannot move out of dereference of `RefMut<'_, &mut I2CDriver<I2C, SDA, SCL>>` move occurs because value has type `esp_idf_hal::i2c::Master<I2C, SDA, SCL>`, which does not implement the `Copy` trait

とエラーが表示されてしまう。

I2CインスタンスはI2CDriver<~~~>構造体が保持しており、
I2CDriver<~~~>構造体はRc<RefCell<I2CDriver<~~~>>>の形でPWMコントローラーが保持している。

Rc<RefCell<I2CDriver<~~~>>>の形でI2Cインスタンスを保持することで、PWMコントローラーでも9軸コントローラーでもI2Cインスタンスを保持することができることは確認している。

このRc<RefCell<I2CDriver<~~~>>>は、Rc::clone()してさらにborrow_mut()すれば、I2CDriverをCopyしなくても参照として保持することができ、インスタンスを実体として関数に渡せるようになるとの認識だったため、エラーがどうしても解決できずにいる。

質問内容

Q1. クレートの関数の引数にインスタンスを渡す時、コピーしなくてもよい方法があるかどうか。
Q2. もしなければ、複数箇所で使用したいインスタンスの所有権を奪われるクレートに対して、どのような回避策があるのか

をご教授お願い致します。

ソースコード

pwm_controller.rs

Rust

use esp_idf_hal::{ gpio::{InputPin, OutputPin}, i2c::{self as esp_i2c_mod},};use std::{cell::RefCell, rc::Rc}; use i2c_driver::i2c::I2CDriver;use i2c_driver::i2c::I2CMasterTrait; use anyhow; use pwm_pca9685::{Address, Channel, Pca9685}; pub struct PwmController<'i2c_driver, I2C, SDA, SCL>where I2C: esp_i2c_mod::I2c, SDA: OutputPin + InputPin, SCL: OutputPin + InputPin,{ pub i2c_driver: Rc<RefCell<&'i2c_driver mut I2CDriver<I2C, SDA, SCL>>>, pub slave_id: u8,} impl<I2C, SDA, SCL> PwmController<'_, I2C, SDA, SCL>where I2C: esp_i2c_mod::I2c, SDA: OutputPin + InputPin, SCL: OutputPin + InputPin,{ pub fn new( i2c_driver: Rc<RefCell<&mut I2CDriver<I2C, SDA, SCL>>>, slave_id: u8, ) -> anyhow::Result<PwmController<I2C, SDA, SCL>> { return Ok(PwmController { i2c_driver, slave_id, }); } // PWMボードのアドレスを取得する pub fn fetch_board_addr(&self) -> String { return "not implement".to_string(); } fn test_pwm(&mut self) { let i2c_driver = Rc::clone(&self.i2c_driver); let i2c = i2c_driver.borrow_mut(); let address = Address::default(); let mut pwm = Pca9685::new(i2c.i2c_instance, address).unwrap(); // This corresponds to a frequency of 60 Hz. pwm.set_prescale(100).unwrap(); // It is necessary to enable the device. pwm.enable().unwrap(); // Turn on channel 0 at 0. pwm.set_channel_on(Channel::C0, 0).unwrap(); // Turn off channel 0 at 2047, which is 50% in // the range `[0..4095]`. pwm.set_channel_off(Channel::C0, 2047).unwrap(); let _ = pwm.destroy(); // Get the I2C device back }} impl<I2C, SDA, SCL> I2CMasterTrait for PwmController<'_, I2C, SDA, SCL>where I2C: esp_i2c_mod::I2c, SDA: OutputPin + InputPin, SCL: OutputPin + InputPin,{ fn get_id(&self) -> u8 { self.slave_id } fn exist_slave(&mut self) -> bool { let mut buffer = [0, 2]; RefCell::borrow_mut(&self.i2c_driver) .read(self.get_id(), &mut buffer) .unwrap(); println!("exist {}, buffer = {:?}", self.get_id(), buffer); return true; }}

i2c.rs

Rust

//! i2cのインスタンスを管理するクラス//! use std::{thread::sleep, time::Duration}; use anyhow::Result;use embedded_hal::prelude::_embedded_hal_blocking_i2c_Read;use esp_idf_hal::{ gpio::{InputPin, OutputPin}, i2c::{self, I2cError},}; pub trait I2CMasterTrait { fn get_id(&self) -> u8; /// センサーが生きているかどうか fn exist_slave(&mut self) -> bool;} pub struct I2CDriver<I2C, SDA, SCL>where I2C: i2c::I2c, SDA: OutputPin + InputPin, SCL: OutputPin + InputPin,{ pub i2c_instance: i2c::Master<I2C, SDA, SCL>,} impl<I2C, SDA, SCL> I2CDriver<I2C, SDA, SCL>where I2C: i2c::I2c, SDA: OutputPin + InputPin, SCL: OutputPin + InputPin,{ pub fn new(i2c: I2C, pins: i2c::MasterPins<SDA, SCL>) -> Result<Self> { let i2c_instance = i2c::Master::new( i2c, pins, i2c::config::MasterConfig::new().timeout(Some(Duration::from_millis(100))), ) .unwrap(); return Ok(I2CDriver { i2c_instance }); } pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), I2cError> { if let Err(e) = self.i2c_instance.read(address, buffer) { println!("read error: {}", e); return Ok(()); } return Ok(()); } pub fn scan_address(&mut self) -> String { println!("created i2c pwm boad instance."); for address in 60..127 { println!("try address= {}", address); let mut ret = [0; 32]; if let Err(e) = self.i2c_instance.read(address, &mut ret) { println!("cant read e:{}", e); continue; } println!("Read Complete."); println!("hit i2c. addr: {:?}", address); println!("receive data = {:?}", ret); sleep(Duration::from_millis(100)); } return "finish".to_string(); }}

エラー発生箇所とエラー文

エラー文は今回の問題が発生した経緯と同じ

イメージ説明

コメントを投稿

0 コメント