pub struct Document<S = Draft> { /* private fields */ }Expand description
The document aggregate root with compile-time state tracking.
The generic parameter S determines which operations are available:
§Typestate Safety
The _state field is private and zero-sized. There is no way to
construct a Document<Validated> except through validate().
§Examples
use hwpforge_core::document::Document;
use hwpforge_core::Metadata;
let doc = Document::with_metadata(Metadata::new().with_title("Report"));
assert!(doc.is_empty());Implementations§
Source§impl<S> Document<S>
impl<S> Document<S>
Source§impl Document<Draft>
impl Document<Draft>
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new empty draft document with default metadata.
§Examples
use hwpforge_core::document::Document;
let doc = Document::new();
assert!(doc.is_empty());Sourcepub fn with_metadata(metadata: Metadata) -> Self
pub fn with_metadata(metadata: Metadata) -> Self
Creates a new draft document with the given metadata.
§Examples
use hwpforge_core::document::Document;
use hwpforge_core::Metadata;
let doc = Document::with_metadata(Metadata::new().with_title("Test"));
assert_eq!(doc.metadata().title.as_deref(), Some("Test"));Sourcepub fn for_each_paragraph_mut<F: FnMut(&mut Paragraph)>(&mut self, f: F)
pub fn for_each_paragraph_mut<F: FnMut(&mut Paragraph)>(&mut self, f: F)
문서의 문단을 문서 순서(pre-order)로 방문한다.
캐시 정규화(Self::strip_layout_caches) 등 전 문단 일괄 변환의
진입점이다. Draft 전용 — Validated 는 typestate 상 불변이므로
비교가 필요하면 검증 전 사본에서 수행한다.
§재귀 대상 (정확한 목록)
섹션마다 본문 → 머리말 → 꼬리말 → 바탕쪽 순으로 돌고, 각 문단은 자신을 먼저 방문한 뒤 run 안으로 내려간다:
- 표: 행 → 셀 → 셀 문단(중첩 표 포함), 그다음 표 캡션
- 도형/글상자: 본문 문단 + 캡션 (타원·다각형 동일; 선·사각형·호· 곡선·연결선은 캡션만)
- 각주·미주: 본문 문단
- 메모: 본문 문단 + 앵커 run 안의 중첩
- 묶음 객체: 자식 컨트롤로 재귀
§방문하지 않는 것 (알려진 갭)
crate::image::Image::caption 안의 문단은 방문하지 않는다.
crate::run::RunContent::Image 는 재귀 대상이 아니기 때문이다.
표·글상자 캡션은 방문되므로 캡션 처리가 비대칭이다 — 의도된 설계가
아니라 갭이며, 재귀 대상을 넓히면 캐시 정규화·편집 파이프라인 등
모든 기존 호출자의 동작이 바뀌므로 픽스처를 갖춘 별도 슬라이스로
다룬다. .docs/followups.md 에 기록돼 있다.
§Examples
use hwpforge_core::document::Document;
use hwpforge_core::page::PageSettings;
use hwpforge_core::paragraph::Paragraph;
use hwpforge_core::section::Section;
use hwpforge_foundation::ParaShapeIndex;
let mut doc = Document::new();
doc.add_section(Section::with_paragraphs(
vec![Paragraph::new(ParaShapeIndex::new(0))],
PageSettings::a4(),
));
let mut count = 0;
doc.for_each_paragraph_mut(|_| count += 1);
assert_eq!(count, 1);Sourcepub fn for_each_paragraph<F: FnMut(&Paragraph)>(&self, f: F)
pub fn for_each_paragraph<F: FnMut(&Paragraph)>(&self, f: F)
Self::for_each_paragraph_mut 의 불변 쌍둥이 — 방문 순서와 재귀
대상이 완전히 같다. 재귀 대상 목록과 이미지 캡션 갭은 그쪽 문서에
있다.
문서를 바꾸지 않고 훑기만 하는 호출자(자산 계획 수집·통계·검증)를
위한 것이다. 순서가 같아야 두 순회를 같은 문단 번호로 짝지을 수
있으므로, 한쪽만 고치면 안 된다 —
layout::tests::immutable_walker_matches_the_mutable_one 이 잠근다.
§Examples
use hwpforge_core::document::Document;
use hwpforge_core::page::PageSettings;
use hwpforge_core::paragraph::Paragraph;
use hwpforge_core::section::Section;
use hwpforge_foundation::ParaShapeIndex;
let mut doc = Document::new();
doc.add_section(Section::with_paragraphs(
vec![Paragraph::new(ParaShapeIndex::new(0))],
PageSettings::a4(),
));
let mut count = 0;
doc.for_each_paragraph(|_| count += 1);
assert_eq!(count, 1);Sourcepub fn strip_layout_caches(&mut self)
pub fn strip_layout_caches(&mut self)
모든 문단의 줄 조판 캐시(Paragraph::layout_cache)를 제거한다.
문서 동등성 비교(admission/golden)의 정규화 단계: 네이티브 입력은 캐시를 보유하고 우리 재인코드 산출물은 미보유가 정상이므로, 비교 전 양쪽 사본에서 이 함수를 호출해 캐시 차이를 제거한다.
§Examples
use hwpforge_core::document::Document;
use hwpforge_core::layout::LayoutCache;
use hwpforge_core::page::PageSettings;
use hwpforge_core::paragraph::Paragraph;
use hwpforge_core::section::Section;
use hwpforge_foundation::ParaShapeIndex;
let mut para = Paragraph::new(ParaShapeIndex::new(0));
para.layout_cache = Some(LayoutCache::default());
let mut doc = Document::new();
doc.add_section(Section::with_paragraphs(vec![para], PageSettings::a4()));
doc.strip_layout_caches();
assert!(doc.sections()[0].paragraphs[0].layout_cache.is_none());Sourcepub fn add_section(&mut self, section: Section)
pub fn add_section(&mut self, section: Section)
Appends a section to the draft document.
§Examples
use hwpforge_core::document::Document;
use hwpforge_core::section::Section;
use hwpforge_core::PageSettings;
let mut doc = Document::new();
doc.add_section(Section::new(PageSettings::a4()));
assert_eq!(doc.section_count(), 1);Sourcepub fn set_metadata(&mut self, metadata: Metadata)
pub fn set_metadata(&mut self, metadata: Metadata)
Sets the document metadata.
Sourcepub fn metadata_mut(&mut self) -> &mut Metadata
pub fn metadata_mut(&mut self) -> &mut Metadata
Returns a mutable reference to the metadata.
Sourcepub fn sections_mut(&mut self) -> &mut [Section]
pub fn sections_mut(&mut self) -> &mut [Section]
Returns a mutable slice of sections.
Sourcepub fn validate(self) -> CoreResult<Document<Validated>>
pub fn validate(self) -> CoreResult<Document<Validated>>
Validates the document structure and transitions to Validated.
Consumes self (move semantics). On success, returns a
Document<Validated>. On failure, returns a CoreError.
§Errors
Returns CoreError::Validation if the document violates any
structural invariant (empty sections, empty paragraphs, etc.).
§Examples
use hwpforge_core::document::Document;
use hwpforge_core::section::Section;
use hwpforge_core::paragraph::Paragraph;
use hwpforge_core::run::Run;
use hwpforge_core::PageSettings;
use hwpforge_foundation::{CharShapeIndex, ParaShapeIndex};
let mut doc = Document::new();
doc.add_section(Section::with_paragraphs(
vec![Paragraph::with_runs(
vec![Run::text("Hello", CharShapeIndex::new(0))],
ParaShapeIndex::new(0),
)],
PageSettings::a4(),
));
let validated = doc.validate().unwrap();
assert_eq!(validated.section_count(), 1);use hwpforge_core::document::Document;
let doc = Document::new(); // empty
assert!(doc.validate().is_err());Trait Implementations§
Source§impl<'de> Deserialize<'de> for Document<Draft>
impl<'de> Deserialize<'de> for Document<Draft>
Source§fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>
impl<S> Eq for Document<S>
Source§impl<S> JsonSchema for Document<S>
impl<S> JsonSchema for Document<S>
Source§fn json_schema(gen: &mut SchemaGenerator) -> Schema
fn json_schema(gen: &mut SchemaGenerator) -> Schema
Source§fn inline_schema() -> bool
fn inline_schema() -> bool
$ref keyword. Read moreAuto Trait Implementations§
impl<S> Freeze for Document<S>where
PhantomData<S>: Freeze,
impl<S> RefUnwindSafe for Document<S>where
PhantomData<S>: RefUnwindSafe,
impl<S> Send for Document<S>where
PhantomData<S>: Send,
impl<S> Sync for Document<S>where
PhantomData<S>: Sync,
impl<S> Unpin for Document<S>where
PhantomData<S>: Unpin,
impl<S> UnsafeUnpin for Document<S>where
PhantomData<S>: UnsafeUnpin,
impl<S> UnwindSafe for Document<S>where
PhantomData<S>: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.