Skip to content

Conversation

qryxip
Copy link
Member

@qryxip qryxip commented Jun 12, 2025

内容

Rust API GuidelinesのInteroperabilityの章に従って基礎的なトレイトを実装する。またPythonの特殊メソッドおよびJavaのインターフェイスについても、適切と考えられるものは全部実装してしまう。

  • C-COMMON-TRAITS基準
    • Debug/__repr__
    • (Partial)Eq/__eq__/Object.equals
    • (Partial)Ord (Rustのnewtypeやenumにのみ実装)
    • Hash (Rustのnewtypeやenumにのみ実装)
    • Clone/Clonable, Copy
    • Default
  • C-CONV-TRAITS基準
    • From/Into
    • AsRef/AsMut
  • C-NUM-FMT基準
    • std::fmt::UpperHex
    • std::fmt::LowerHex
    • std::fmt::Octal
    • std::fmt::Binary

最終的に実装したのは以下の通り。

  • Rust API
    • Debug for
      • AudioQuery
      • UserDictWordBuilder
      • {blocking,nonblocking}.onnxruntime.LoadOnce
      • {blocking,nonblocking}.VoiceModelFile
      • {blocking,nonblocking}.OpenJtalk
      • {blocking,nonblocking}.Synthesizer
      • {blocking,nonblocking}.synthesizer.*
    • PartialEq for
      • StyleMeta
      • AudioQuery
      • UserDictWord
    • {PartialOrd,Ord} for
      • AccelerationMode
      • UserDictWordType
    • Hash for
      • CharacterVersion
      • AccelerationMode
    • {AsRef,AsMut} for CharacterVersion
    • {UpperHex,LowerHex,Octal,Binary} for StyleId
    • Into<u32> for StyleId (via From)
  • Python API
    • __repr__ for
      • {blocking,asyncio}.VoiceModelFile
      • {blocking,asyncio}.Onnxruntime
      • {blocking,asyncio}.VoiceModelFile
      • {blocking,asyncio}.OpenJtalk
      • {blocking,asyncio}.UserDict
  • Java API
    • Object.equals for
      • SupportedDevices
      • StyleMeta
      • CharacterMeta
      • Mora
      • AccentPhrase
      • AudioQuery
    • Cloneable for
      • SupportedDevices
      • StyleMeta
      • CharacterMeta
      • Mora

またAudioFeatureにも色々実装。

以下判断メモ。

  • ==/equalsはできる限り実装する。Rust以外の言語ではあらゆるオブジェクトを==/equalsで比較してしまえるため
  • Rustにおいては:
    • Defaultの実装には慎重に
    • (Partial)Ordの実装も慎重に
    • PartialじゃないEq、およびHashの実装も慎重に。f32などを入れたくなったときに困るため
    • newtypeはその限りではないので、中身が実装しているトレイトを制覇するつもりで書く
    • ビルダー型はDebugだけ実装しておく
    • Debugをどうするかは悩みどころ。標準ライブラリのドキュメントでは"Generally speaking, you should just derive a Debug implementation"とは言われているが、実際の慣習としてはカスタマイズは普通に行われている。標準ライブラリにおいてすら、例えばVecRccapacityとか{strong,weak}_countといった情報も持っているはずだがそれらの表示はされない。[a, b, c]のように表示される。では常に簡略化される方向なのかというとそうでもなく、各ライブラリの作者の思想に依る。特にstruct Newtype(i32)みたいなやつをNewtype(42)と表示するか42と表示するかは、下手すると同じライブラリ内ですらブレている例があったりする (e.g. ndarray)
      • 悩むが、全部簡略化する方向に倒してしまう。newtypeも中身だけ表示する方針にする
      • 既存のDenug実装があるStyleIdとかについては、別PRで変更を行うことにする
      • Session内のLoadedModelsについては、Sessionについては表示せずマップキー側のVoiceModelIdだけ表示するようにする。ONNXとしての入出力シグネチャまで含まれてしまいかなり邪魔なため
      • AudioFeature::internal_stateの表示も_にしておく
  • Pythonにおいては:
    • __repr__の実装は作法に従う。どう書くかは悩むが、とりあえず<voicevox_core.blocking.型名 rust_api=<'RustのDebug表示'>>のようにする
      • Rustと違ってpprintでpretty printとかはできないので、かなり見づらくはある
  • Javaにおいては:
    • Lombokが激烈に欲しくなってきたが、このPRでは全部手で実装することにする

関連 Issue

その他

@qryxip qryxip changed the title feat(rust,python,java): 基礎的なインターフェイスを完備 feat(rust,python,java): 基礎的なインターフェイスを取り揃える Jun 12, 2025
@qryxip
Copy link
Member Author

qryxip commented Jun 15, 2025

@sevenc-nanashi 今review requestをヒホさんと名無し。さんの二人に出していますが、どちらかと言うとRustとPythonとJavaの知識が揃っている名無し。さんの意見を伺えたらなと思っています。
もしお忙しくなければ、どうでしょう…?

[追記] 実装の判断基準をこのPRのdescriptionに書いたので、先に読むとわかりやすいかも

_marker: PhantomData<fn(A) -> A>,
}

#[derive(derive_more::Debug)]
#[debug(bounds())]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここって意味あるんですかね?derive_moreの説明読んでるんですけどあまりよくわからなく

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#[derive(std::fmt::Debug)]と同じような挙動をすると考えると、where A: Debugという不必要なトレイト境界が足されちゃうからですね。
Rustのderiveはあまり頭がよくない - 簡潔なQ

…と思ったけど、このbounds()消しても動きますね。#[derive(std::fmt::Debug)]と挙動が違う。ドキュメントではuse derive_more::Debug; #[derive(Debug)]と紹介されていたところderive_moreを完全に信用しきれずに#[derive(derive_more::Debug)]と書いてきたわけですが、マジで非互換性があったとは!

we’ll try our best to infer trait bounds

いやいやいや…

考えたのですが、"our best"というのもよくわからないのでbounds()は明示的に指定しておきたいなという気持ちになりました。

Copy link
Member Author

@qryxip qryxip Jun 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"our best"というのもよくわからないのでbounds()は明示的に指定しておきたい

ちょっと考えなおして、郷に入れば郷に従うようにしました。use derive_more::Debugせずに#[derive(derive_more::Debug)]と書くなら大丈夫なはず…?
b0981a0 (#1100)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ということでご指摘ありがとうございました!

@qryxip
Copy link
Member Author

qryxip commented Jun 15, 2025

  • 3b50931 (#1100): #[debug(bounds)]#[debug(bound)]は同じ意味のようだが、どうも後者の方が正式な雰囲気を感じるので後者に統一
  • 67629c0 (#1100): <AudioFeature as Debug>において、internal_stateの表示を_とする
  • 380716a (#1100): Python APIのAudioFeature.__repr__を忘れていたので実装

@qryxip qryxip requested a review from sevenc-nanashi June 15, 2025 13:15
@qryxip qryxip requested a review from sevenc-nanashi June 16, 2025 18:39
Copy link
Member

@sevenc-nanashi sevenc-nanashi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

特に問題なさそう。

@qryxip
Copy link
Member Author

qryxip commented Jun 19, 2025

以下の一点だけ入れてマージしようと思います。

@qryxip qryxip removed the request for review from Hiroshiba June 19, 2025 16:50
@qryxip qryxip merged commit ab68bfb into VOICEVOX:main Jun 19, 2025
29 checks passed
@qryxip qryxip deleted the pr/feat-rust-python-java-impl-common-interfaces-and-methods branch June 19, 2025 17:00
qryxip added a commit to qryxip/voicevox_core that referenced this pull request Jul 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants