fzyzcjy / flutter_rust_bridge

Flutter/Dart <-> Rust binding generator, feature-rich, but seamless and simple.
https://fzyzcjy.github.io/flutter_rust_bridge/
MIT License
4.17k stars 288 forks source link

Again: Running panic with `RustArc<dynamic>` #2312

Open dbsxdbsx opened 6 days ago

dbsxdbsx commented 6 days ago

win10, frb 2.4.0 Similar to this issue err2 still, it is hard to diagnose to the real place trigger it. Anyway, finally, I find it is due to this dart code:

 Future<List<MediaDoc>> _fetchMediaDocsForType(
      String mainType, String subType) async {
    final targetMediaType = CustomMediaType(
      mainType: mainType,
      subType: subType,
    );
    return Api1.initMediaDocs(
      cmsList: _cmsList,
      onliveFilePath: Assets.onliveMediaPath,
      number: BigInt.from(40), // TODO: 初始化时固定更新40个节目
      targetMediaType: targetMediaType,
    );
  }

the correspding rust code:

pub async fn init_media_docs(
    cms_list: CmsList,
    onlive_file_path: String,
    number: usize, // 所属分类要获取的总数,若category为None,则`number`代表所有总数
    target_media_type: Option<CustomMediaType>,
    media_name_to_search: Option<String>,
) -> Vec<MediaDoc> {
    if let Some(target_media_type) = target_media_type {
        if target_media_type.main_type == "直播" {
            return media::init_all_onlive_media_docs(&onlive_file_path, number).await;
        }
        media::init_all_cms_media_docs(cms_list, number, target_media_type)
            .await
            .unwrap_or_default()
    } else {
        return media::init_media_docs_by_name(cms_list, number, &media_name_to_search.unwrap())
            .await
            .unwrap_or_default();
    }
}

why I am sure this fn is the core issue part? Because when replacing the media::init_all_cms_media_docs(cms_list, number, target_media_type)... part into vec![], the issue disappeared.

Here, the MediaDoc is defined like this :

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[frb(opaque)]
pub struct MediaDoc {
    pub names: Vec<String>, // 对于外国电影,需要这个字段
    pub ids: Vec<CmsMediaId>,
    pub has_updated: bool,   // 是否已经更新过了除了names和ids外的所有细节
    pub uuid: String,        // 提供给dart侧作为hero效果的mark标识(目前在更新玩细节后才更新)
    pub images: Vec<String>, // 一般选第一张图作为海报图
    pub year: String,
    pub(crate) area: String, // 大陆、港台...
    pub scores: Vec<VideoScore>,
    pub content: String,
    pub director: String,
    pub actors: Vec<String>,
    pub custom_type: CustomMediaType, // 这个是在App中的自定义类别,不是cms中的类别
    pub cms_type: String, // 这个是cms中的类别名称,只要是cms的内容,应该都是不为空的, 直播类的暂填为“直播”
    pub tags: Vec<String>, // 这个是具体的内容标签,可从vod_tag和vod_class提取(可能为空)
    pub remarks: Vec<String>, // 常见于cms源的`vod_remarks`,有类似于“完结”、“更新至12集”的信息,该字段每个元素代表某一个cms源的remark信息
    // TODO:delete pub category: String, //这个是我自定义的题材大类,如:直播、番剧、电影...可结合cms的type_id进行归类
    // TODO:delete pub types: Vec<VideoTypeId>, //这个是针对各个站点的type类型
    pub play_urls: Vec<PlayUrls>, // 每个元素代表了具体某一集的播放链接
}

the #[frb(opaque)] is essential, otherwise, the generation would be failed with an ambiguity warning. Then, I tried to fix it:

pub async fn init_media_docs(
    cms_list: CmsList,
    onlive_file_path: String,
    number: usize, // 所属分类要获取的总数,若category为None,则`number`代表所有总数
    target_media_type: Option<CustomMediaType>,
    media_name_to_search: Option<String>,
) -> Vec<RustAutoOpaque<MediaDoc>> {
    if let Some(target_media_type) = target_media_type {
        if target_media_type.main_type == "直播" {
            return media::init_all_onlive_media_docs(&onlive_file_path, number)
                .await
                .into_iter()
                .map(RustAutoOpaque::new)
                .collect();
        }
        media::init_all_cms_media_docs(cms_list.clone(), number, target_media_type.clone())
            .await
            .unwrap_or_default()
            .into_iter()
            .map(RustAutoOpaque::new)
            .collect()
    } else {
        media::init_media_docs_by_name(cms_list.clone(), number, &media_name_to_search.unwrap())
            .await
            .unwrap_or_default()
            .into_iter()
            .map(RustAutoOpaque::new)
            .collect()
    }
}

But still, the issue is still there.

Actually, for this issue, I would rather this likely issue could be fixed totally so that users never need to care about RustAutoOpaque

fzyzcjy commented 6 days ago

I am not sure whether the error is caused by the functions you present (possibly also by combination with usage somewhere else).

As for why sometimes RustAutoOpaque is needed, this is usually because of Rust's rules. For example, if you want A or Option<A> or Vec<A> as argument of a function, then you have no choice but to own the instance of A. That means you will never be able to use that same instance anywhere else. But if RustAutoOpaque<A>, then it is as if Arc<A> and thus shared ownership, and no problem.

dbsxdbsx commented 6 days ago

so, that means there is no need to modify the return type of any rust fn, there should be someplace elsewhere triggered the running panic.

fzyzcjy commented 6 days ago

I guess so